[英]Includes in a (semi) generic Repository
我試圖弄清楚如何使用新的EF Code First東西,但是卻很難弄清楚如何將Include
功能改編為半通用Repository類。 (我說是半泛型的,因為類不是泛型的,只是方法。所以,我有一個實質上包裝了聚合的存儲庫,您可以與該聚合中的所有實體進行交互,而不僅僅是單個實體。 )
我的情況是,我有一個實體,該實體有一個始終需要加載的子對象,然后有其他僅選擇性加載的子對象,我想在我的存儲庫方法中包含一個簡單的bool參數。 像這樣:
public S GetByID<S>(int entityID, bool loadChildren = false) where S : class
{
DbSet<S> set = _context.Set<S>();
if (loadChildren)
set = FullInclude<S>(set);
else
set = DefaultInclude<S>(set);
return set.Find(entityID);
}
protected virtual DbSet<S> DefaultInclude<S>(DbSet<S> set) where S : class
{
// base implementation just returns the set
// derived versions would attach Includes to the set before returning it
return set;
}
protected virtual DbSet<S> FullInclude<S>(DbSet<S> set) where S : class
{
// base implementation just returns the set
// derived versions would attach Includes to the set before returning it
return set;
}
那是我的基本存儲庫,我希望能夠在派生類中重寫那些XyzInclude
方法。 但是我需要使用非通用實現來覆蓋它們,這顯然在語言級別上不起作用。
使用Linq2Sql真的很容易,因為我只需配置一個DataLoadOptions
對象並將其附加到上下文。 在關閉DbSet
的Include
API之后,我為如何做到這一點感到DbSet
。 我正在尋找有關簡單實施戰略模式或類似模式的建議。
編輯:我想我問題的實質是關於用非泛型派生版本覆蓋泛型方法。 我正在尋找一種可以允許我執行此操作的模式或技術。 擴展方法是我正在考慮的一件事,但是如果有人有擴展方法,則更喜歡一種“純粹的”解決方案。
除非使類完全通用,否則不可能:
public class BaseRepo<S>
{
protected virtual DbSet<S> DefaultInclude(DbSet<S> set) {return set;}
}
public class ProductRepo : BaseRepo<Product>
{
protected override DbSet<Product> DefaultInclude(DbSet<Product> set)
{
return set.Include("...");
}
}
只是以為我會以最終得到的解決方案重新審視這一點。 我的存儲庫不是完全通用的,但是所有方法都是如此,因此我需要一種存儲任何實體類型的include的方法,並能夠在調用該類型的方法時將其提取出來。
我從拉吉斯拉夫的答案借這里 ,我可以重溫這個設計只是對衍生庫定義的每個單獨的方法定義自己的包括因為有什么包括什么不包括足夠的不同組合,如果重復代碼的點點在幾個地方定義相同的包含可能是值得的。 但是無論如何,這是當前的設計並且可以正常工作...
基礎資料庫:
public abstract class Repository : IQueryableRepository, IWritableRepository
{
private readonly DbContext _context;
private readonly Dictionary<Type, LambdaExpression[]> _includes = new Dictionary<Type, LambdaExpression[]>();
protected Repository(DbContextBase context)
{
_context = context;
RegisterIncludes(_includes);
}
protected abstract void RegisterIncludes(Dictionary<Type, LambdaExpression[]> includes);
protected S GetSingle<S>(Expression<Func<S, bool>> query, bool getChildren = false) where S : class
{
IQueryable<S> entities = _context.Set<S>().AsNoTracking();
if (query != null)
entities = entities.Where(query);
entities = ApplyIncludesToQuery<S>(entities, getChildren);
return entities.FirstOrDefault();
}
private IQueryable<S> ApplyIncludesToQuery<S>(IQueryable<S> entities, bool getChildren) where S : class
{
Expression<Func<S, object>>[] includes = null;
if (getChildren && _includes.ContainsKey(typeof(S)))
includes = (Expression<Func<S, object>>[])_includes[typeof(S)];
if (includes != null)
entities = includes.Aggregate(entities, (current, include) => current.Include(include));
return entities;
}
}
派生的存儲庫只需要在一個地方定義它們的包含,然后在調用查詢方法時,只需指定是否要包含子項即可(請參見上面的getChildren
)。
public class DerivedRepository : Repository
{
public DerivedRepository(DbContext context)
: base(context) { }
protected override void RegisterIncludes(Dictionary<Type, LambdaExpression[]> includes)
{
includes.Add(typeof(ParentType), new Expression<Func<ParentType, object>>[] {
p => p.SomeChildReference.SomeGrandchild,
p => p.SomeOtherChildReference
});
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.