存储库模式和实体框架包含

时间:2012-05-10 09:00:23

标签: entity-framework repository-pattern

我正在使用EF的存储库模式,我认为我已经在它上面销售,但仍有一个问题;

如果我想加载一个实体,那么最好的方法是什么?

例如,我有一个映射到实体的存储库:

public class EFFooRepository : IFooRepository
{
     public IQueryable<Foo> GetFoo()
     {
        .....
     }
}

如果我想获取Foo和Bar对象

,该怎么办?
db.Foo.Include("Bar")

但我的存储库只返回Foo,那么我是否需要创建另一个方法GetFooAndBar?

有更好的方法吗?

2 个答案:

答案 0 :(得分:1)

我经历过同样的经历。当我实现Repository模式时,我希望能够使用IQueryable&lt; T>和IEnumerable&lt; T>那个DbSet&lt; T>提供的工具,不暴露DbSet&lt; T> (好旧信息隐藏)

因此我认为让所有IQueryable / IEnumerable函数调用DbSet的相应函数就足够了。 T>在存储库中。

直到今天,这对我所有的IQueryable来说已经足够了T>功能。今天我发现除了IQueryable.Include有你描述的相同问题。没有编译器错误,但未加载数据。

经过广泛的结果后,我发现原因在QueryableExtensions.Include Method (IQueryable, String)

的MSDN描述中有所描述
  

如果存在这样的方法,则此扩展方法将调用源IQueryable对象的Include(String)方法。 如果源IQueryable没有匹配方法,则此方法不执行任何操作。

所以我所要做的就是在我的存储库中编写一个匹配的include语句,它将调用相应的DbSet存储库。 IQueryable / IEnumerable函数只调用DbSet的相应函数:

public class Repository<T> : 
    System.Linq.IQueryable<T>, System.Collections.Generic.IEnumerable<T>,
    System.Linq.IQueryable, System.Collections.IEnumerable
    where T : class, new()
{
    public Repository(DbContext dbContext)
    {
        this.dbContext = dbContext;
        this.dbSet = dbContext.Set<T>();
    }

    public readonly DbSet<T> dbSet;
    private readonly DbContext dbContext;

    public virtual DbQuery<T> Include(string path)
    {
        return this.dbSet.Include(path);
    }

    // other Repository functions: Find / Add / Update / Remove etc

为了完整性,IQueryable / IEnumerable实现:

    #region IQueryable
    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
        return ((IQueryable<T>)this.dbSet).GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return ((IEnumerable)this.dbSet).GetEnumerator();
    }

    Type IQueryable.ElementType
    {
        get { return ((IQueryable<T>)this.dbSet).ElementType; }
    }

    System.Linq.Expressions.Expression IQueryable.Expression
    {
        get { return ((IQueryable)this.dbSet).Expression; }
    }

    IQueryProvider IQueryable.Provider
    {
        get { return ((IQueryable)this.dbSet).Provider; }
    }
    #endregion IQueryable

现在以下工作,包括地址:

using (MyDbContext dbContext = new MyDbContext(...))
{
    Repository<Customer> customers = new Repository<Customer>(dbContext);
    var happyCustomers = customers
        .Include(customer => customer.Address)
        .Where(customer => customer.IsHappy);
    Show(happyCustomers);
}

答案 1 :(得分:0)

如果您启用了延迟加载,则可以稍后加载Bar(当您要访问该属性时)。但是如果你想编写一个同时加载数据FooBar的方法,则需要编写特定的存储库方法。