1

我知道 LINQ 不能使用未映射到数据库列的属性,但我不明白为什么一个 LINQ 语句在非静态方法中工作,但在一个方法中尝试时出现此错误。

这是我的工作方法:

private TemplatesAPIContext db = new TemplatesAPIContext();

// GET api/Template
public IQueryable<TemplateDto> GetTemplates()
{
    return db.TemplateModels.Include(t => t.Categories).Select(
        x => new TemplateDto
        {
            TemplateID = x.TemplateID,
            Name = x.Name,
            HTMLShowcase = x.HTMLShowcase,
            ShortDescription = x.ShortDescription,
            CreationDate = x.CreationDate,
            Downloads = x.Downloads,
            Tags = x.Tags,
            Categories = db.CategoryModels
                            .Where(c => x.Categories.Where(a => a.TemplateID == x.TemplateID)
                            .Select(a => a.CategoryID).Contains(c.CategoryID))
        }
    );
}

我不想重复这个复杂的 DTO 构建(我实际上仍然需要添加一些其他关系,它会变得更加复杂)并在控制器中的每个方法上输入它,所以我想制作一个 lambda 表达式并将其传递给方法。

所以我这样做了:

private static readonly Expression<Func<TemplateModel, TemplateDto>> AsTemplateDto =
    x => new TemplateDto
    {
        TemplateID = x.TemplateID,
        Name = x.Name,
        HTMLShowcase = x.HTMLShowcase,
        ShortDescription = x.ShortDescription,
        CreationDate = x.CreationDate,
        Downloads = x.Downloads,
        Tags = x.Tags,
        Categories = new TemplatesAPIContext().CategoryModels
                            .Where(c => x.Categories.Where(a => a.TemplateID == x.TemplateID)
                            .Select(a => a.CategoryID).Contains(c.CategoryID))
    };

希望致电:

// GET api/Template
public IQueryable<TemplateDto> GetTemplates()
{
    return db.TemplateModels.Include(t => t.Categories).Select(AsTemplateDto);
}

但这会返回这个错误,这对我来说没有意义,因为它是完全相同的查询,唯一的区别是我需要在 lambda 中实例化 dbContext,因为我不能将控制器中实例化的那个用作 lambda 表达式是静态的。

错误

LINQ to Entities 不支持指定的类型成员“CategoryModels”。仅支持初始化程序、实体成员和实体导航属性。

4

2 回答 2

2

重要的是在查询中使用与进行查询的上下文相同的上下文,以便查询提供程序了解您要执行的操作。因此,您所需要的只是一种复制特定于给定上下文的表达式的方法,这并不难,您已经完成了几乎所有的工作。

//TODO rename method as appropriate
private static Expression<Func<TemplateModel, TemplateDto>> 
    CreateTemplateDTO(TemplatesAPIContext context)
{
    return x => new TemplateDto
    {
        TemplateID = x.TemplateID,
        Name = x.Name,
        HTMLShowcase = x.HTMLShowcase,
        ShortDescription = x.ShortDescription,
        CreationDate = x.CreationDate,
        Downloads = x.Downloads,
        Tags = x.Tags,
        Categories = context.CategoryModels
            .Where(c => x.Categories.Where(a => a.TemplateID == x.TemplateID)
            .Select(a => a.CategoryID).Contains(c.CategoryID))
    };
}

现在你可以写:

public IQueryable<TemplateDto> GetTemplates()
{
    return db.TemplateModels.Include(t => t.Categories)
        .Select(CreateTemplateDTO(db));
}
于 2013-11-14T22:31:16.510 回答
0

您的第一个方法是一个简单的表达式树,它只包含树节点中的简单操作(例如将 A 分配给 B),因此它可以很容易地编译成 SQL 查询。
另一个方法包含 TemplatesAPIContext 的实例化。数据库查询是不可能的。

于 2013-11-14T22:32:10.377 回答