So stellen Sie den Entity Framework-Datenkontext schreibgeschützt ein

112

Ich muss einen Entity Framework-Datenkontext für Plugins von Drittanbietern verfügbar machen. Der Zweck besteht darin, diesen Plugins zu erlauben, nur Daten abzurufen und keine Einfügungen, Aktualisierungen oder Löschungen oder andere Befehle zur Datenbankänderung auszugeben. Wie kann ich also einen Datenkontext oder eine Entität schreibgeschützt machen?

Harindaka
quelle
3
Geben Sie ihnen einen Kontext mit einem Benutzer, der keinen Schreibzugriff auf die Datenbank hat.
vcsjones
Vielen Dank. Ich benutze eine SQLite-Datenbank. Ich habe gerade herausgefunden, dass es im schreibgeschützten Modus über eine Verbindungszeichenfolgenoption geöffnet werden kann.
Harindaka
2
Gib ihnen keine DbContext, gib ihnen eine IQueryableoder mehrere.
ta.speot.is

Antworten:

178

Neben der Verbindung mit einem schreibgeschützten Benutzer können Sie noch einige andere Dinge mit Ihrem DbContext tun.

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>();
    }
}
Bricelam
quelle
1
Es war offensichtlich, dass Sie ein "Insider" sind :) - Dies ist viel interessanter als eine "schreibgeschützte" Verbindung
NSGaga-meistens inaktiv
6
Beachten Sie, dass die AsNoTracking()Verwendung das verzögerte Laden unmöglich macht.
Tom Pažourek
@ TomPažourek Ich weiß nicht, ob das stimmt ... Ich denke, EF erstellt immer noch faul ladende Proxys, aber die Auflösung der Identität könnte etwas seltsam werden.
Bricelam
3
Vergessen Sie nicht, auch zu überschreiben public override Task<int> SaveChangesAsync().
Pete
7
Verlassen Sie sich nicht darauf, denn es (context as IObjectContextAdapter).ObjectContext.SaveChanges()wird immer noch funktionieren. Die beste Wahl ist, den DbContext(string nameOrConnectionString);Contstructor mit einer Lese- / Schreib-Verbindungszeichenfolge für die Datenbankerstellung und einer anschließenden schreibgeschützten Verbindungszeichenfolge zu verwenden.
Jürgen Steinblock
31

Im Gegensatz zu der akzeptierten Antwort halte ich es für besser, die Komposition der Vererbung vorzuziehen . Dann müssten keine Methoden wie SaveChanges beibehalten werden, um eine Ausnahme auszulösen. Warum brauchen Sie überhaupt solche Methoden? Sie sollten eine Klasse so gestalten, dass sich ihr Verbraucher nicht täuschen lässt, wenn er sich die Liste der Methoden ansieht. Die öffentliche Schnittstelle sollte mit der tatsächlichen Absicht und dem eigentlichen Ziel der Klasse übereinstimmen, während in der akzeptierten Antwort mit SaveChanges nicht impliziert wird, dass der Kontext schreibgeschützt ist.

An Stellen, an denen ein schreibgeschützter Kontext erforderlich ist, z. B. auf der Leseseite des CQRS- Musters, verwende ich die folgende Implementierung. Es bietet seinem Verbraucher nichts anderes als Abfragefunktionen.

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

Mit ReadOnlyDataContext können Sie nur auf Abfragefunktionen von DbContext zugreifen. Angenommen, Sie haben eine Entität mit dem Namen Order. Dann würden Sie die ReadOnlyDataContext-Instanz wie folgt verwenden.

readOnlyDataContext.Set<Order>().Where(q=> q.Status==OrderStatus.Delivered).ToArray();
Ehsan Mirsaeedi
quelle
Ermöglicht diese Methode die Verwendung eines SQL-Logins nur für db_datareader? Mit einem Standard-DBContext löst EF die Berechtigung CREATE TABLE aus, die verweigert wird, selbst wenn mein Abfragecode keine SaveChanges () enthält.
Erreichen des
2
Und lassen Sie es vonIDisposable
hkarask
Anstatt Set <> zu verwenden, würde ich Query <> vorschlagen. public IQueryable<TEntity> Get<TEntity>() where TEntity : class { return _dbContext.Query<TEntity>().AsNoTracking(); }
Allan Nielsen
@ Karkar - nicht sicher, ob ich das tun würde. Da dieser Aufruf den DbContext nicht erstellt hat, sollte er nicht entsorgt werden. Dies könnte dazu führen, dass einige Fehler später schwer aufzuspüren sind.
Allan Nielsen
@AllanNielsen Query <> ist als veraltet markiert. Demnach sollte Set <> verwendet werden.
Frank