【问题标题】:Can't change Entity Framework members to protected无法将实体框架成员更改为受保护
【发布时间】:2016-12-20 13:31:20
【问题描述】:

我的应用程序中有以下 DbContext 类可以正常工作:

public partial class BaseContext : DbContext
{
    public virtual DbSet<Customer> Customers { get; set; }
    public virtual DbSet<Contact> Contacts { get; set; }
}

public partial class MyAppContext : BaseContext
{
    public new IQueryable<Customer> Customers()
    {
        return base.Customers.Where(n => n.Active == true);
    }

    public new IQueryable<Contact> Contacts()
    {
        return base.Contacts.Where(n => n.Active == true);
    }
}

我希望在我的应用程序中对客户或联系人的所有呼叫都过滤掉非活动记录。这种方法效果很好,但有人可能会在我的基本上下文中意外调用客户或联系人,我想避免这种情况。

我认为理想的解决方案是使我的基本上下文中的成员受到保护,以便它们只能由 MyAppContext 访问,但这会失败,因为在 2 个 DbSet 中从未加载任何数据。例如

public partial class BaseContext : DbContext
{
    protected virtual DbSet<Customer> Customers { get; set; }
    protected virtual DbSet<Contact> Contacts { get; set; }
}

当我将这些设置为受保护时,不会加载任何数据,当它们公开时一切都很好(但这会公开这些我想避免的)。

有人对如何解决这个问题有任何建议吗?

【问题讨论】:

  • 我认为这与 EF 内部的工作方式有关。它将尝试从外部传播违反访问修饰符的属性。
  • 我知道它适用于对象的属性,那么如何制作 DbSets protected internal
  • 这是伪封装。消费者将始终可以访问context.Set&lt;T&gt;()。此外,这不会阻止通过导航属性获得不活跃的客户。软删除需要更严格的方法。

标签: c# .net asp.net-mvc entity-framework


【解决方案1】:

一种解决方案可能是不在您的基类上使用DbSet&lt;&gt; 属性,而是使用流畅的 API 来声明您的实体类型:

public partial class BaseContext : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Customer>();
        modelBuilder.Entity<Contact>();
    }
}

然后在MyAppContext,你可以这样声明你的属性:

public IQueryable<Customer> Customers =>
    Set<Customer>.Where(n => n.Active == true);
public IQueryable<Contact> Contacts =>
    Set<Contact>.Where(n => n.Active == true);

【讨论】:

    【解决方案2】:

    您可以为它们提供一个实现,而不是使它们成为自动属性。

    public partial class BaseContext : DbContext
    {
        protected virtual DbSet<Customer> Customers { get { return this.Set<Customer>(); } }
        protected virtual DbSet<Contact> Contacts { get { return this.Set<Contact>(); } }
    }
    

    【讨论】:

      【解决方案3】:

      您可以使用空的DbContext,然后将它的实例传递给这样的通用存储库:

      public class GenericRepository<T> : IGenericRepository where T : class, new()
      {
          private readonly DbContext _context;
          private readonly DbSet<T> _set;
      
          public GenericRepository(DbContext context)
          {
              _context = _db;
              _set = _context.Set<T>();
          }
      
          public IQueryable<T> Query => _set.Where(m=>m.Active == true);
      
          public virtual void Add(T entity) => _set.Add(entity);
      
          public virtual void Update(T entity) => this._context.Entry(entity).State = EntityState.Modified;
      
          public virtual void Delete(T entity) =>  _set.Remove(entity);
      }
      

      此模式允许您对实体操作进行非常精细的分级控制。您还可以使用不同的查询/更新逻辑实现不同的存储库。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-01-30
        • 1970-01-01
        • 1970-01-01
        • 2011-01-02
        • 2014-06-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多