Cara membuat Entity Framework Data Context Readonly

112

Saya perlu mengekspos Entity Framework Data Context ke plugin pihak ketiga. Tujuannya adalah untuk memungkinkan plugin ini mengambil data saja dan tidak membiarkan mereka mengeluarkan penyisipan, pembaruan atau penghapusan atau perintah modifikasi database lainnya. Karenanya, bagaimana saya bisa membuat konteks atau entitas data hanya-baca.

Harindaka
sumber
3
Beri mereka konteks dengan pengguna yang tidak memiliki akses tulis ke database.
vcsjones
Terima kasih. Saya menggunakan database SQLite. Baru saja mengetahui bahwa itu dapat dibuka dalam mode hanya baca melalui opsi string koneksi.
Harindaka
2
Jangan beri mereka a DbContext, beri mereka satu IQueryableatau beberapa.
ta.speot. Adalah

Jawaban:

178

Selain menghubungkan dengan pengguna hanya-baca, ada beberapa hal lain yang dapat Anda lakukan untuk DbContext Anda.

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.dll
sumber
1
sudah jelas Anda adalah 'orang dalam' :) - ini jauh lebih menarik daripada koneksi 'hanya-baca'
NSGaga-kebanyakan-tidak aktif
6
Perhatikan bahwa AsNoTracking()penggunaan pemuatan lambat tidak akan memungkinkan.
Tom Pažourek
@ TomPažourek Saya tidak tahu apakah itu benar ... Saya pikir EF masih membuat proksi pemuatan lambat, tetapi resolusi identitas mungkin sedikit aneh.
bricelam
3
Jangan lupa untuk menimpa public override Task<int> SaveChangesAsync()juga.
Pete
7
Jangan mengandalkan ini, karena (context as IObjectContextAdapter).ObjectContext.SaveChanges()akan tetap berfungsi. Pilihan terbaik adalah menggunakan DbContext(string nameOrConnectionString);contstructor dengan string koneksi baca / tulis untuk hal-hal pembuatan database dan string koneksi hanya baca sesudahnya.
Jürgen Steinblock
33

Berbeda dengan jawaban yang diterima, saya percaya akan lebih baik untuk lebih memilih komposisi daripada warisan . Maka tidak perlu menyimpan metode seperti SaveChanges untuk membuat pengecualian. Selain itu, mengapa Anda perlu memiliki metode seperti itu sejak awal? Anda harus mendesain kelas sedemikian rupa sehingga konsumennya tidak tertipu ketika melihat daftar metodenya. Antarmuka publik harus sejalan dengan maksud dan tujuan kelas yang sebenarnya sementara dalam jawaban yang diterima memiliki SaveChanges tidak berarti bahwa Konteks hanya-baca.

Di tempat-tempat di mana saya perlu memiliki konteks hanya-baca seperti di sisi Baca pola CQRS , saya menggunakan implementasi berikut. Itu tidak memberikan apa pun selain kemampuan Querying kepada konsumennya.

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

Dengan menggunakan ReadOnlyDataContext, Anda hanya dapat memiliki akses ke kemampuan kueri DbContext. Misalkan Anda memiliki entitas bernama Order, maka Anda akan menggunakan instance ReadOnlyDataContext dengan cara seperti di bawah ini.

readOnlyDataContext.Set<Order>().Where(q=> q.Status==OrderStatus.Delivered).ToArray();
Ehsan Mirsaeedi
sumber
Apakah metode ini mengizinkan penggunaan login sql hanya db_datareader? Dengan standar DBContext EF melempar izin CREATE TABLE ditolak bahkan ketika kode kueri saya tidak menyertakan SaveChanges ().
mencapainexus
2
Dan jadikan itu mewarisi dariIDisposable
hkarask
Alih-alih menggunakan Set <>, saya menyarankan Query <>. public IQueryable<TEntity> Get<TEntity>() where TEntity : class { return _dbContext.Query<TEntity>().AsNoTracking(); }
Allan Nielsen
@hkarask - tidak yakin saya akan melakukan itu. Karena panggilan ini tidak membuat DbContext, panggilan ini tidak boleh dibuang. Ini dapat menyebabkan beberapa bug sulit dilacak nanti.
Allan Nielsen
Kueri @AllanNielsen <> ditandai tidak berlaku lagi. Menurutnya Set <> harus digunakan.
Frank