使用Linq表达式

时间:2016-07-26 22:43:58

标签: c# entity-framework linq

我在使用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方法。

3 个答案:

答案 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()