使用带有AsEnumerable

时间:2017-03-02 14:36:40

标签: c# entity-framework linq ienumerable iqueryable

TL; DR

AsEnumerable() IQueryable()使用更安全(例如,它是否已作为ToList()执行),以便为错误automapper Only parameterless constructors and initializers are supported in LINQ to Entities.找到解决方法(见下文) ?

换句话说,AsEnumerable() 上使用IQueryable()会产生什么影响,尤其是在将Where()链接到它时。

请阅读以下内容,了解完整背景和信息

长版

我正在为我的存储库层实现抽象,因为我必须能够从JSON文件,XML文件以及EntityFramework(数据库)中读取数据。

问题描述

在执行这样的代码时,我在使用错误automapper Only parameterless constructors and initializers are supported in LINQ to Entities.投影我的EF实体时遇到了问题:

public IEnumerable<Person> All() {
    return _dataContext
        .People
        .Select(p => new Person(p.Id, p.FirstName, p.LastName));                
}

作为参考,这是我的DbContext,因此您看到以上_dataContext.People返回IQueryable<EFPerson>

public class EFDataContext : DbContext
{       
    public IDbSet<EFPerson> People { get; set; }

    public EFDataContext() 
        : this(Settings.Default.EFDataContextConnectionString) { }
    public EFDataContext(string nameOrConnectionString)
        : this(() => nameOrConnectionString) { }
    public EFDataContext(Func<string> connectionStringProvider) 
        : base(connectionStringProvider()) { }

    protected override void OnModelCreating(DbModelBuilder modelBuilder) {
        modelBuilder.Entity<EFPerson>()
            .HasKey(p => p.Id)
            .ToTable(Settings.Default.PeopleTable);
    }
}

我的解决方案

我不想使用AutoMapper,我也不想让我的域名实体拥有setters - 因为他们需要对商业模式我来说是不可变的/只读的写作。

我想出的解决方案是使用.AsEnumerable(),然后使用我的域实体的构造函数进行投影:

public IEnumerable<Person> All() {
    return _dataContext
        .People
        .AsEnumerable()
        .Select(p => new Person(p.Id, p.FirstName, p.LastName));                
}

代码运行得很快,之后我也可以在域实体上进行.Where预测。 我认为这是安全的,因为我的理解是.AsEnumerable不会像.ToList那样立即评估。

问题回顾

我的问题因此,我的假设是正确的。这样做是否是一种安全的解决方法,或者我应该对它进行不同的建模 - 使用AutoMapper还是在我的服务层/存储库的EntityFramework实现中编写更长的逻辑?

1 个答案:

答案 0 :(得分:1)

由于你的问题非常广泛,我将描述我的解决方案: 在Entity Framework中使用您的域实体:

public class EFDataContext : DbContext
{       
    public IDbSet<Person> People { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder) {
        modelBuilder.Entity<Person>()
            .HasKey(p => p.Id)
            .ToTable(Settings.Default.PeopleTable);
    }
}

根据需要设计实体:

public class Person
{
    private Person() //for EF
    {
    }
    public Person(string name) //for me
    {
        Name = name;
    }
    public int Id { get; private set; }
    public string Name { get; private set; }
    public string LastName { get; private set; }
}

查询:

public IEnumerable<Person> All() {
    return _dataContext
        .People
        .AsEnumerable();                
}

为什么我在这里使用AsEnumerable?只是为了隐藏我的数据库及其IQueryable。 如您所见,EF允许使用域对象。