如何使实体框架数据上下文为只读


112

我需要向第3方插件公开Entity Framework Data Context。目的是允许这些插件仅获取数据,而不允许它们发出插入,更新或删除或任何其他数据库修改命令。因此,如何使数据上下文或实体变为只读。


3
为他们提供一个对数据库没有写权限的用户上下文。
vcsjones'5

谢谢。我正在使用SQLite数据库。刚刚发现它可以通过连接字符串选项以只读模式打开。
Harindaka

2
不要给他们一个DbContext,给他们一个IQueryable或几个。
ta.speot。是

Answers:


178

除了与只读用户建立连接外,您还可以对DbContext执行其他一些操作。

public class MyReadOnlyContext : DbContext
{
    // Use ReadOnlyConnectionString from App/Web.config
    public MyContext()
        : base("Name=ReadOnlyConnectionString")
    {
    }

    // Don't expose Add(), Remove(), etc.
    public DbQuery<Customer> Customers
    {
        get
        {
            // Don't track changes to query results
            return Set<Customer>().AsNoTracking();
        }
    }

    public override int SaveChanges()
    {
        // Throw if they try to call this
        throw new InvalidOperationException("This context is read-only.");
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // Need this since there is no DbSet<Customer> property
        modelBuilder.Entity<Customer>();
    }
}

1
很明显,您是一个“内部人” :)-这比“只读”连接有趣得多
NSGaga-2012年

6
请注意,使用AsNoTracking()将无法使用延迟加载。
TomPažourek'16

@TomPažourek我不知道这是不是真的...我认为EF仍会创建延迟加载代理,但身份解析可能会有些奇怪。
bricelam '16

3
不要忘记也要覆盖public override Task<int> SaveChangesAsync()
皮特2016年

7
不要依赖于此,因为它(context as IObjectContextAdapter).ObjectContext.SaveChanges()仍然可以工作。最好的选择是将DbContext(string nameOrConnectionString);构造函数与用于数据库创建内容的读/写连接字符串一起使用,然后再使用只读连接字符串。
的JürgenSteinblock

32

与公认的答案相反,我相信最好是继承而不是继承。这样就无需保留诸如SaveChanges之类的方法来引发异常。此外,为什么首先需要使用这种方法?您应该以一种让其使用者在查看其方法列表时不会上当的方式设计类。公共接口应该与类的实际意图和目标保持一致,而在接受的答案中,具有SaveChanges并不意味着Context是只读的。

在需要具有只读上下文的地方,例如CQRS模式的“读取”端,我使用以下实现。除了向使用者提供查询功能外,它没有提供任何其他功能。

public class ReadOnlyDataContext
{
    private readonly DbContext _dbContext;

    public ReadOnlyDataContext(DbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public IQueryable<TEntity> Set<TEntity>() where TEntity : class
    {
        return _dbContext.Set<TEntity>().AsNoTracking();
    }
}

通过使用ReadOnlyDataContext,您只能访问DbContext的查询功能。假设您有一个名为Order的实体,那么您将以如下方式使用ReadOnlyDataContext实例。

readOnlyDataContext.Set<Order>().Where(q=> q.Status==OrderStatus.Delivered).ToArray();

此方法是否仅允许使用db_datareader sql登录?使用标准的DBContext,即使我的查询代码不包含任何SaveChanges(),EF也会抛出CREATE TABLE权限被拒绝。

2
并使其继承自IDisposable
hkarask

建议不要使用Set <>,而是建议Query <>。 public IQueryable<TEntity> Get<TEntity>() where TEntity : class { return _dbContext.Query<TEntity>().AsNoTracking(); }
艾伦·尼尔森

@hkarask-不知道我会那样做。由于此调用未创建DbContext,因此不应处置它。这可能会导致以后很难发现一些错误。
艾伦·尼尔森

@AllanNielsen Query <>已标记为已弃用。根据它应该使用Set <>。
弗兰克
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.