在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表达式中使用方法

这是因为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()