Entity Frameworkデータコンテキストを読み取り専用にする方法


112

Entity Framework Data Contextをサードパーティのプラグインに公開する必要があります。目的は、これらのプラグインがデータのみをフェッチできるようにし、挿入、更新、削除、またはその他のデータベース変更コマンドを発行できないようにすることです。したがって、データコンテキストまたはエンティティを読み取り専用にするにはどうすればよいですか。


3
データベースへの書き込みアクセス権がないユーザーとのコンテキストを提供します。
vcsjones

ありがとう。SQLiteデータベースを使用しています。接続文字列オプションを介して読み取り専用モードで開くことができることがわかりました。
ハリンダカ

2
彼らにDbContextを与えないでくださいIQueryable
ta.speot.is 2017

回答:


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-mostly-inactive

6
を使用AsNoTracking()すると、遅延読み込みを使用できなくなることに注意してください。
TomPažourek、2016

@TomPažourekそれが本当かどうかはわかりません... EFでも遅延読み込みプロキシが作成されると思いますが、ID解決が少し奇妙になる可能性があります。
bricelam 2016

3
public override Task<int> SaveChangesAsync()同様にオーバーライドすることを忘れないでください。
Pete

7
(context as IObjectContextAdapter).ObjectContext.SaveChanges()まだ機能するため、これに依存しないでください。最良の選択はDbContext(string nameOrConnectionString);、データベース作成用の読み取り/書き込み接続文字列と、後で読み取り専用接続文字列を使用してコンストラクタを使用することです。
ユルゲンスタインブロック2017

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(); }
Allan Nielsen

@hkarask-私がそうするかどうかわからない。この呼び出しはDbContextを作成しなかったため、破棄するべきではありません。これにより、後でバグを追跡することが困難になる可能性があります。
Allan Nielsen

@AllanNielsen Query <>は非推奨とマークされています。それによると、Set <>を使用する必要があります。
フランク
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.