我已找到适合我的答案。我在上下文中将我的DbSet属性声明为派生接口,例如:
IDerivedDbSet<Customer> Customers { get; set; }
IDerivedDbSet<CustomerOrder> CustomerOrders { get; set; }
我的实现包括一个私有的IDbSet,它在构造函数中被赋值,例如:
public class DerivedDbSet<T> : IDerivedDbSet<T> where T : class
{
private readonly IDbSet<T> _dbSet;
public DerivedDbSet(IDbSet<T> dbSet)
{
this._dbSet = dbSet;
}
...
}
我的派生DbContext接口的实现隐藏了Set<>()方法,如下所示:
new public IDerivedSet<TEntity> Set<TEntity>() where TEntity : class
{
if (this._dbSets == null)
{
this._dbSets = new Dictionary<Type, object>();
}
if (this._dbSets.ContainsKey(typeof (TEntity)))
{
return (IDerivedSet<TEntity>) this._dbSets[typeof (TEntity)];
}
var resolvedSet = new GlqcSet<TEntity>(base.Set<TEntity>());
this._dbSets.Add(typeof(TEntity), resolvedSet);
return resolvedSet;
}
派生的DbContext会返回一个新构造的IDerivedSet,或者选择在字典中缓存引用。在派生的DbContext中,我从构造函数调用一个方法,该方法使用类型反射遍历DbContext的属性,并使用自己的Set方法分配值/引用。请参见此处:
private void AssignDerivedSets()
{
var properties = this.GetType().GetProperties();
var iDerivedSets =
properties.Where(p =>
p.PropertyType.IsInterface &&
p.PropertyType.IsGenericType &&
p.PropertyType.Name.StartsWith("IDerivedSet") &&
p.PropertyType.GetGenericArguments().Count() == 1).ToList();
foreach (var iDerivedSet in iDerivedSets)
{
var entityType = iDerivedSet.PropertyType.GetGenericArguments().FirstOrDefault();
if (entityType != null)
{
var genericSet = this.GetType().GetMethods().FirstOrDefault(m =>
m.IsGenericMethod &&
m.Name.StartsWith("Set") &&
m.GetGenericArguments().Count() == 1);
if (genericSet != null)
{
var setMethod = genericSet.MakeGenericMethod(entityType);
iDerivedSet.SetValue(this, setMethod.Invoke(this, null));
}
}
}
}
这对我来说非常有帮助。我的上下文类具有可导航的集合属性,这些属性是我的集合类型的实现,该类型继承了IDbSet接口。这意味着我可以在我的集合类型上包含查询方法,以便查询可以进行单元测试,而不是使用Queryable类的静态扩展。(Queryable方法由我的自定义方法直接调用)。
_personSet = new PersonSet{ MyProperty = 10 };
。 - Arturo Martinez