我在使用Entity Framework访问数据库的Web API项目中使用LINQ。我使用脚手架
创建了我的API控制器我们不希望Web API公开我们的EF模型类,因此我们使用的是DTO。我修改了控制器方法以使用DTO,并使用“Translate”方法在模型类和DTO之间复制特定实体的值,并在类中的几个方法中使用它。
对于这篇文章,我使用了一个简单的Person类,它有三个属性:FirstName,LastName,MiddleName。
public IQueryable<PersonDto> GetPersons()
{
var personDtos = from p in db.Persons
order by p.LastName, p.FirstName
select new PersonDto()
{
FirstName = p.FirstName,
LastName = p.LastName,
MiddleName = p.MiddleName
};
return personDtos;
}
private PersonDto Translate(Person p)
{
if (person == null)
return null;
return new PersonDto()
{
FirstName = p.FirstName,
LastName = p.LastName,
MiddleName = p.MiddleName
}
}
正如您所看到的,通过在LINQ表达式中调用Translate方法,可以获得重构机会,如下所示:
public IQueryable<PersonDto> GetPersons()
{
var personDtos = from p in db.Persons
order by p.LastName, p.FirstName
select Translate(p);
return personDtos;
}
看起来不错,除非我运行它,我得到一个例外:
LINQ to Entities无法识别“翻译”方法
有没有办法让这项工作?我们的数据模型中的一些类具有相当多的属性,因此如果可能的话,最好在这里调用Translate方法。
答案 0 :(得分:2)
原因LINQ to Entities
必须将表达式转换为SQL查询,并且您的方法无法翻译,因为它不知道如何操作。一种方法是调用AsEnumerable()
并在LINQ to objects
上调用您的方法,而不是
var personDtos = from p in db.Persons.AsEnumerable()
order by p.LastName, p.FirstName
select Translate(p);
答案 1 :(得分:1)
LinqToEntities不知道如何将您的方法Translate()更改为可以在数据库中执行的内容。 AsEnumerable()将确保在调用后处理发生在客户端:
var personDtos = (from p in db.Persons
order by p.LastName, p.FirstName
select p)
.AsEnumerable()
.Translate(p);
会让你非常接近。但是,Translate()只占用一个人,而不是IEnumerable。您可以将其更改为
private IEnumerable<PersonDto> Translate(IEnumerable<Person> persons)
{
if (persons == null) yield break;
foreach (var p in persons)
{
yield return new PersonDto()
{
FirstName = p.FirstName,
LastName = p.LastName,
MiddleName = p.MiddleName
}
}
}
答案 2 :(得分:-1)
您可以使用 ProjectTo AutoMapper 的可查询扩展程序。
db.Persons.ProjectTo<PersonDTO>().ToList()