Come rendere Entity Framework Data Context di sola lettura


112

Devo esporre un contesto dati di Entity Framework a plug-in di terze parti. Lo scopo è quello di consentire a questi plugin di recuperare solo i dati e di non consentire loro di emettere inserimenti, aggiornamenti o eliminazioni o altri comandi di modifica del database. Quindi come posso rendere un contesto o un'entità dati di sola lettura.


3
Fornisci loro un contesto con un utente che non ha accesso in scrittura al database.
vcsjones

Grazie. Sto usando un database SQLite. Ho appena scoperto che può essere aperto in modalità di sola lettura tramite un'opzione della stringa di connessione.
Harindaka

2
Non dare loro un DbContext, dagli uno IQueryableo più.
ta.speot.is

Risposte:


178

Oltre alla connessione con un utente di sola lettura, ci sono alcune altre cose che puoi fare per il tuo 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
era ovvio che sei un "uomo interiore" :) - questo è molto più interessante di una connessione "di sola lettura"
NSGaga, per lo più inattivo,

6
Si noti che l'utilizzo AsNoTracking()renderà impossibile utilizzare il caricamento lento.
Tom Pažourek

@ TomPažourek Non so se sia vero ... Penso che EF crei ancora proxy a caricamento lento, ma la risoluzione dell'identità potrebbe diventare un po 'strana.
bricelam

3
Non dimenticare di eseguire public override Task<int> SaveChangesAsync()anche l' override .
Pete

7
Non fare affidamento su questo, perché (context as IObjectContextAdapter).ObjectContext.SaveChanges()funzionerà ancora. La scelta migliore è usare il DbContext(string nameOrConnectionString);contstructor con una stringa di connessione di lettura / scrittura per le cose di creazione del database e successivamente una stringa di connessione di sola lettura.
Jürgen Steinblock

33

Al contrario della risposta accettata, credo che sarebbe meglio privilegiare la composizione rispetto all'eredità . Quindi non sarebbe necessario mantenere metodi come SaveChanges per generare un'eccezione. Inoltre, perché è necessario disporre di tali metodi in primo luogo? Dovresti progettare una classe in modo che il suo consumatore non si lasci ingannare quando guarda il suo elenco di metodi. L'interfaccia pubblica dovrebbe essere in linea con l'intento e l'obiettivo effettivi della classe mentre nella risposta accettata avere SaveChanges non implica che Context sia di sola lettura.

In luoghi in cui è necessario disporre di un contesto di sola lettura come nel lato di lettura del pattern CQRS , utilizzo la seguente implementazione. Non fornisce nient'altro che funzionalità di query al suo consumatore.

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

Utilizzando ReadOnlyDataContext, puoi avere accesso solo alle funzionalità di query di DbContext. Supponiamo che tu abbia un'entità denominata Order, quindi useresti l'istanza di ReadOnlyDataContext in un modo come di seguito.

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

Questo metodo consente l'utilizzo di un accesso solo sql db_datareader? Con un DBContext standard EF genera l'autorizzazione CREATE TABLE negata anche quando il codice della mia query non include SaveChanges ().
raggiungimento

2
E IDisposable
fallo

Invece di usare Set <>, suggerirei Query <>. public IQueryable<TEntity> Get<TEntity>() where TEntity : class { return _dbContext.Query<TEntity>().AsNoTracking(); }
Allan Nielsen

@hkarask - non sono sicuro che lo farei. Poiché questa chiamata non ha creato il DbContext, non dovrebbe eliminarlo. Questo potrebbe portare ad alcuni bug difficili da rintracciare in seguito.
Allan Nielsen

@AllanNielsen Query <> è contrassegnato come obsoleto. Secondo esso Set <> dovrebbe essere usato.
Frank il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.