在Linq表达式中使用方法
本文关键字:使用方法 表达式 Linq | 更新日期: 2023-09-27 17:58:40
我在一个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方法。
这是因为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);
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
}
}
}
您可以使用ProjectTo自动映射器的可查询扩展。
db.Persons.ProjectTo<PersonDTO>().ToList()