有没有办法从DbSet继承?我想添加一些新属性,如:
public class PersonSet : DbSet<Person>
{
public int MyProperty { get; set; }
}
但我不知道如何在我的DbContext中实例化它
public partial MyContext : DbContext
{
private PersonSet _personSet;
public PersonSet PersonSet
{
get
{
_personSet = Set<Person>(); // Cast Error here
_personSet.MyProperty = 10;
return _personSet;
}
}
}
我怎样才能做到这一点?
答案 0 :(得分:5)
一种解决方案是创建一个实现IDbSet的类,并将所有操作委托给一个真正的DbSet实例,这样就可以存储状态。
public class PersonSet : IDbSet<Person>
{
private readonly DbSet<Person> _dbSet;
public PersonSet(DbSet<Person> dbSet)
{
_dbSet = dbSet;
}
public int MyProperty { get; set; }
#region implementation of IDbSet<Person>
public Person Add(Person entity)
{
return _dbSet.Add(entity);
}
public Person Remove(Person entity)
{
return _dbSet.Remove(entity);
}
/* etc */
#endregion
}
然后在你的DbContext中,为你的自定义DbSet添加一个getter:
public class MyDbContext: DbContext
{
public DbSet<Person> People { get; set; }
private PersonSet _personSet;
public PersonSet PersonSet
{
get
{
if (_personSet == null)
_personSet = new PersonSet( Set<Person>() );
_personSet.MyProperty = 10;
return _personSet;
}
set
{
_personSet = value;
}
}
}
答案 1 :(得分:4)
我找到了一个适合我的答案。我在我的上下文中将我的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&lt;&gt;()方法,如下所示:
new public IDerivedSet<TEntity> Set<TEntity>() where TEntity : class
{
//Instantiate _dbSets if required
if (this._dbSets == null)
{
this._dbSets = new Dictionary<Type, object>();
}
//If already resolved, return stored reference
if (this._dbSets.ContainsKey(typeof (TEntity)))
{
return (IDerivedSet<TEntity>) this._dbSets[typeof (TEntity)];
}
//Otherwise resolve, store reference and return
var resolvedSet = new GlqcSet<TEntity>(base.Set<TEntity>());
this._dbSets.Add(typeof(TEntity), resolvedSet);
return resolvedSet;
}
派生的DbContext返回一个新构造的IDerivedSet,或者选择它在Dictionary中缓存的引用。在派生的DbContext中,我从构造函数中调用一个方法,该方法使用类型反射来遍历DbContexts属性,并使用它自己的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));
}
}
}
}
为我服务。我的上下文类具有我的set类型的可导航集属性,它实现了继承IDbSet的派生接口。这意味着我可以在我的set类型中包含查询方法,以便查询是可单元测试的,而不是使用Queryable类中的静态扩展。 (可以通过我自己的方法直接调用Queryable方法。)
答案 2 :(得分:2)
我使用另一个变量解决了这个问题,以实例化“常规”DbSet。
private DbSet<Person> _persons { get; set; }
public PersonDbSet<Person> Persons { get { return new PersonDbSet(_persons); } }
这样实体框架可以识别实体,但我仍然可以使用自己的DbSet类。
答案 3 :(得分:1)
我知道这已经很老了,OP可能已经开始了,但我自己也想知道同样的事情。 EF在运行时填充MyContext中的DbSets。
我刚刚创建了MyDbSet&lt; T&gt;继承自DbSet&lt; T&gt;并且替换了对DbSet&lt; T&gt;的所有引用。在MyContext中使用我的派生类。运行我的程序无法实例化任何属性。
接下来,我尝试将属性设置为IDbSet&lt; T&gt;因为DbSet&lt; T&gt;实现这个接口。这可行。
进一步研究DbSet的构造函数是受保护的和内部的(受保护的构造函数无论如何都调用内部构造函数)。因此,MS很难推出自己的版本。您可以通过反射访问内部构造函数,但无论如何EF都不会构造派生类。
我建议编写一个扩展方法将功能插入到DbSet对象中,但是如果你想存储状态,你就会陷入困境。