简体   繁体   English

继承自DbSet <T> 用于添加属性的目的

[英]Inherits from DbSet<T> with the purposes to add property

Is there a way to inherits from DbSet? 有没有办法从DbSet继承? I want to add some new properties, like this: 我想添加一些新属性,如下所示:

public class PersonSet : DbSet<Person>
{
    public int MyProperty { get; set; }
}

But I don't know how to instantiate it in my DbContext 但我不知道如何在我的DbContext中实例化它

public partial MyContext : DbContext
{
    private PersonSet _personSet; 
    public PersonSet PersonSet
    {
        get 
        {
            _personSet = Set<Person>(); // Cast Error here
            _personSet.MyProperty = 10;
            return _personSet;
        }
    }
}

How can I achieve this? 我怎样才能做到这一点?

One solution is to create a class that implements IDbSet and delegates all operations to a real DbSet instance, so you can store state. 一种解决方案是创建一个实现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
}

Then in your DbContext, put a getter for your Custom DbSet: 然后在你的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;
        }
    }

}

I have found an answer that works for me. 我找到了一个适合我的答案。 I declare my DbSet properties as my derived interface in my context, eg: 我在我的上下文中将我的DbSet属性声明为我的派生接口,例如:

IDerivedDbSet<Customer> Customers { get; set; }
IDerivedDbSet<CustomerOrder> CustomerOrders { get; set; }

My implementation includes a private IDbSet which which is assigned in the constructor eg: 我的实现包括一个私有IDbSet,它在构造函数中分配,例如:

 public class DerivedDbSet<T> : IDerivedDbSet<T> where T : class
 {
    private readonly IDbSet<T> _dbSet;

    public DerivedDbSet(IDbSet<T> dbSet)
    {
        this._dbSet = dbSet;
    }
 ...
 }

My implementation of a derived DbContext interface hides the Set<>() method like so: 我的派生DbContext接口的实现隐藏了Set <>()方法,如下所示:

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;
    }

The derived DbContext returns a newly constructed IDerivedSet or picks it's reference cached in a Dictionary. 派生的DbContext返回一个新构造的IDerivedSet,或者选择它在Dictionary中缓存的引用。 In the derived DbContext I call a method from the constructor which uses type reflection to go through the DbContexts properties and assigns a value/reference using it's own Set method. 在派生的DbContext中,我从构造函数中调用一个方法,该方法使用类型反射来遍历DbContexts属性,并使用它自己的Set方法分配值/引用。 See here: 看这里:

 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));
                }
            }
        }
    }

Works a treat for me. 为我服务。 My context class has navigable set properties of my set type that implements a derived interface inheriting IDbSet. 我的上下文类具有我的set类型的可导航集属性,它实现了继承IDbSet的派生接口。 This means I can include query methods on my set type, so that queries are unit testable, instead of using the static extensions from the Queryable class. 这意味着我可以在我的set类型中包含查询方法,以便查询是可单元测试的,而不是使用Queryable类中的静态扩展。 (The Queryable methods are invoked directly by my own methods). (Queryable方法由我自己的方法直接调用)。

I solved this using another variable to instantiate the "regular" DbSet. 我使用另一个变量解决了这个问题,以实例化“常规”DbSet。

    private DbSet<Person> _persons { get; set; }
    public PersonDbSet<Person> Persons { get { return new PersonDbSet(_persons); } }

This way entityframework recognizes the Entity but I can still use my own DbSet class. 这种方式entityframework识别实体,但我仍然可以使用我自己的DbSet类。

I know this is really old and the OP has probably moved on but I was just wondering the same thing myself. 我知道这真的很老了,OP可能已经开始了,但我自己也想知道同样的事情。 EF populates the DbSets inside your MyContext at run time. EF在运行时填充MyContext中的DbSets。

I just created MyDbSet<T> that inherits from DbSet<T> and the replaced all references to DbSet<T> with my derived class in MyContext. 我刚创建了继承自DbSet <T>的MyDbSet <T>,并用MyContext中的派生类替换了对DbSet <T>的所有引用。 Running my program failed to instantiate any of the properties. 运行我的程序无法实例化任何属性。

Next I tried setting the properties to IDbSet<T> since DbSet<T> implements this interface. 接下来,我尝试将属性设置为IDbSet <T>,因为DbSet <T>实现了此接口。 This DOES work. 这个工作。

Investigating further, the constructors for DbSet are protected and internal (the protected one calls the internal one anyway). 进一步研究,DbSet的构造函数受到保护并且是内部的(受保护的构造函数无论如何都会调用内部构造函数)。 So MS have made it pretty hard to roll your own version. 因此,MS很难推出自己的版本。 You may be able to access the internal constructors through reflection but chances are that EF will not construct your derived class anyway. 您可以通过反射访问内部构造函数,但无论如何EF都不会构造派生类。

I would suggest writing an extension method to plug the functionality into the DbSet object, however you're stuck if you want to store state. 我建议编写一个扩展方法来将功能插入到DbSet对象中,但是如果你想存储状态就会被卡住。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM