【问题标题】:EF Eager loading include multipleEF Eager loading 包括多个
【发布时间】:2014-02-05 10:17:58
【问题描述】:

我有这个存储库:

public class Repository<T> : IRepository<T> where T : class
{
    private readonly DbContext context;
    private readonly DbSet<T> dbEntitySet;

    public Repository(DbContext context)
    {
        if (context == null)
            throw new ArgumentNullException("context");

        this.context = context;
        this.dbEntitySet = context.Set<T>();
    }

    public IEnumerable<T> GetAll()
    {
        return this.dbEntitySet;
    }

    public IEnumerable<T> GetAll(string include)
    {
        return this.dbEntitySet.Include(include);
    }

    public IEnumerable<T> GetAll(string[] includes)
    {
        IQueryable<T> query = context.Set<T>();
        foreach (var include in includes)
            query.Include(include);

        return query;
    }

    public void Create(T model)
    {
        this.dbEntitySet.Add(model);
    }

    public void Update(T model)
    {
        this.context.Entry<T>(model).State = EntityState.Modified;
    }

    public void Remove(T model)
    {
        this.context.Entry<T>(model).State = EntityState.Deleted;
    }

    public void Dispose()
    {
        this.context.Dispose();
    }
}

我有一个如下所示的服务:

public class Service<T> where T : class
{
    private readonly IRepository<T> repository;

    protected IRepository<T> Repository
    {
        get { return this.repository; }
    }

    internal Service(IUnitOfWork unitOfWork)
    {
        this.repository = unitOfWork.GetRepository<T>();
    }
}

我的页面服务如下所示(简化):

public class PageService : Service<Page>
{

    // ...

    public IList<Page> GetPublished()
    {
        return this.Repository.GetAll(new string[] { "ForbiddenUsers", "ForbiddenGroups" }).Where(model => model.Published).ToList();
    }

    // ...

}

为了清楚起见,我的页面如下所示:

public enum PageType
{
    Root,
    System,
    Page,
    Link,
    Group
}

public partial class Page
{
    public int Id { get; set; }
    public System.DateTime DateCreated { get; set; }
    public string CreatedById { get; set; }
    public Nullable<System.DateTime> DateModified { get; set; }
    public string ModifiedById { get; set; }
    public string CompanyId { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public string FileName { get; set; }

    public string Path { get; set; }
    public string ViewData { get; set; }
    public string ViewTitle { get; set; }

    public string Link { get; set; }
    public bool Published { get; set; }
    public PageType Type { get; set; }
    public int Order { get; set; }
    public string Lineage { get; set; }
    public Nullable<int> ParentId { get; set; }
    public bool Restricted { get; set; }
    public bool Deleted { get; set; }

    public Company Company { get; set; }
    public User CreatedBy { get; set; }
    public User ModifiedBy { get; set; }
    public Page Parent { get; set; }
    public MenuPage MenuPage { get; set; }
    public ICollection<Page> Pages { get; set; }
    public ICollection<User> ForbiddenUsers { get; set; }
    public ICollection<Group> ForbiddenGroups { get; set; }
}

当我运行此代码时,ForbiddenUsersForbiddenGroups 始终为空。 如果我检查调用堆栈,我可以看到生成的查询如下所示:

SELECT 
[Extent1].[Id] AS [Id], 
[Extent1].[DateCreated] AS [DateCreated], 
[Extent1].[CreatedById] AS [CreatedById], 
[Extent1].[DateModified] AS [DateModified], 
[Extent1].[ModifiedById] AS [ModifiedById], 
[Extent1].[CompanyId] AS [CompanyId], 
[Extent1].[Name] AS [Name], 
[Extent1].[Description] AS [Description], 
[Extent1].[FileName] AS [FileName], 
[Extent1].[Path] AS [Path], 
[Extent1].[ViewData] AS [ViewData], 
[Extent1].[ViewTitle] AS [ViewTitle], 
[Extent1].[Link] AS [Link], 
[Extent1].[Published] AS [Published], 
[Extent1].[Type] AS [Type], 
[Extent1].[Order] AS [Order], 
[Extent1].[Lineage] AS [Lineage], 
[Extent1].[ParentId] AS [ParentId], 
[Extent1].[Restricted] AS [Restricted], 
[Extent1].[Deleted] AS [Deleted]
FROM [dbo].[Pages] AS [Extent1]

如您所见,这完全忽略了我的包含。

如果我将服务方法更改为:

public IList<Page> GetPublished()
{
    return this.Repository.GetAll("ForbiddenUsers").Where(model => model.Published).ToList();
}

运行我的代码,ForbiddenUsers 现在已填充,调用堆栈显示正确生成的查询(太大,无法粘贴到此处)。

我需要允许多个包含,但我不知道为什么它们不起作用....

任何帮助将不胜感激......

【问题讨论】:

    标签: c# entity-framework eager-loading


    【解决方案1】:

    下面是 C#6 中的示例。另外,注意使用 nameof 操作符使代码更易于维护,这样在重命名时不需要手动更新属性名的字符串值。

    // Assign the property names
    var navigablePropertyNames = new[]
    {
        nameof(ParentEntity.Id),
        nameof(ParentEntity.Name),
        nameof(ParentEntity.Description)
    };
    
    // Do the inclusion
    GetAll(navigablePropertyNames);
    

    所以对于您的具体要求:

    public IEnumerable<T> GetAll(params string[] inclusions)
    {
        var qry = this.dbEntitySet.AsQueryable();
    
        foreach(var inclusion in inclusions)
        {
            qry  = qry.Include(inclusion);
        }
    
        return qry;
    }
    

    用法:

    // either 
    var resultSet1 = GetAll(nameof(ParentEntity.Id),
        nameof(ParentEntity.Name),
        nameof(ParentEntity.Description));
    
    // or
    var propertyNames = new[] {
        nameof(ParentEntity.Id),
        nameof(ParentEntity.Name),
        nameof(ParentEntity.Description)};
    
    var resultSet2 = GetAll(propertyNames);
    

    【讨论】:

      【解决方案2】:

      您应该将包含的查询分配回您的查询变量,因为QueryableExtensions.Include 会创建新的DbQuery&lt;T&gt; 而不是修改现有的。另外我建议您使用params 包含路径:

      public IEnumerable<T> GetAll(params string[] includes)
      {
          IQueryable<T> query = context.Set<T>();
          foreach (var include in includes)
              query = query.Include(include);
      
          return query;
      }
      

      这将允许您传递所有包含的路径而无需显式创建数组:

      public IList<Page> GetPublished()
      {
          return Repository.GetAll("ForbiddenUsers", "ForbiddenGroups")
                           .Where(model => model.Published)
                           .ToList();
      }
      

      【讨论】:

      • 感谢你们两个 :) 我也喜欢 params 的东西,这就是为什么我将你标记为答案
      【解决方案3】:

      试试

         foreach (var include in includes)
              query = query.Include(include);
      
          return query;
      

      【讨论】:

      • 其实我们几乎是同时发的,你甚至快一点:)
      猜你喜欢
      • 1970-01-01
      • 2019-04-27
      • 2011-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-09
      相关资源
      最近更新 更多