lambda表达式中的C#LINQ to SQL指定类型成员
我知道LINQ不能使用未映射到数据库列的属性,尽管我不明白为什么一个LINQ语句在非静态方法中工作,但我在尝试在一个方法中工作时遇到了这个错误 以下是我的工作方法:lambda表达式中的C#LINQ to SQL指定类型成员,c#,linq,entity-framework,lambda,asp.net-web-api,C#,Linq,Entity Framework,Lambda,Asp.net Web Api,我知道LINQ不能使用未映射到数据库列的属性,尽管我不明白为什么一个LINQ语句在非静态方法中工作,但我在尝试在一个方法中工作时遇到了这个错误 以下是我的工作方法: private TemplatesAPIContext db = new TemplatesAPIContext(); // GET api/Template public IQueryable<TemplateDto> GetTemplates() { return db.TemplateModels.Inc
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))
}
);
}
private TemplatesAPIContext db=new TemplatesAPIContext();
//获取api/模板
公共IQueryable GetTemplates()
{
返回db.TemplateModels.Include(t=>t.Categories)。选择(
x=>新模板到
{
TemplateID=x.TemplateID,
Name=x.Name,
HTMLShowcase=x.HTMLShowcase,
ShortDescription=x.ShortDescription,
CreationDate=x.CreationDate,
下载=x.下载,
标签=x。标签,
类别=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))
};
私有静态只读表达式AsTemplateDto=
x=>新模板到
{
TemplateID=x.TemplateID,
Name=x.Name,
HTMLShowcase=x.HTMLShowcase,
ShortDescription=x.ShortDescription,
CreationDate=x.CreationDate,
下载=x.下载,
标签=x。标签,
Categories=新模板sapiContext().categorimodels
.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);
}
//获取api/模板
公共IQueryable GetTemplates()
{
返回db.TemplateModels.Include(t=>t.Categories)。选择(AsTemplateDto);
}
但这返回了这个错误,这对我来说没有意义,因为它是完全相同的查询,唯一的区别是我需要在lambda中实例化dbContext,因为我不能使用在控制器中实例化的dbContext,因为lambda表达式是静态的
错误
LINQ to实体中不支持指定的类型成员“CategoryModels”。仅支持初始值设定项、实体成员和实体导航属性
在查询中使用与进行查询的上下文相同的上下文是很重要的,这样查询提供者才能理解您试图做什么。所以你所需要的是一种复制特定于给定上下文的表达式的方法,这并不难,你已经完成了几乎所有的工作
//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))
};
}
//TODO根据需要重命名方法
私有静态表达式
CreateTemplateDTO(TemplatesAPIContext上下文)
{
返回x=>newtemplatedto
{
TemplateID=x.TemplateID,
Name=x.Name,
HTMLShowcase=x.HTMLShowcase,
ShortDescription=x.ShortDescription,
CreationDate=x.CreationDate,
下载=x.下载,
标签=x。标签,
类别=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));
}
public IQueryable GetTemplates()
{
返回db.TemplateModels.Include(t=>t.Categories)
.选择(CreateTemplateDTO(db));
}
您的第一个方法是一个简单的表达式树,它只包含树节点中的简单操作(如将a分配给B),因此可以轻松地将其编译为SQL查询。另一个方法包含TemplatesAPIContext的实例化。无法进行数据库查询。您正在尝试从一个上下文查询另一个上下文?无论如何,EF无法将该方法转换为SQL查询(您认为会是怎样的?)让我感到困惑的是,它在第一个示例中工作。我想我要问的是,如何编写lambda表达式以产生与第一个示例相同的查询?嗯,我想我尝试将上下文作为参数传递给表达式,但它给了我一些错误,让我再试一次。@francisco.preller您几乎肯定无法将其作为字段来执行;它需要是一个方法,或者充其量是一个属性,但是一个方法最好。啊,得到了它,必须把它变成一个方法,而不仅仅是一个属性。谢谢,这很有效。老兄,我是如此接近>@francisco.preller是的,当你完成了95%的工作时,我几乎为获得解决方案的荣誉而感到难过。我很抱歉不得不问,但从昨晚起我就一直在为此而头痛:P