Cách làm cho ngữ cảnh dữ liệu khung thực thể chỉ đọc


112

Tôi cần hiển thị Ngữ cảnh dữ liệu khung thực thể cho các plugin của bên thứ ba. Mục đích là để cho phép các plugin này chỉ lấy dữ liệu và không cho phép chúng đưa ra các lệnh chèn, cập nhật hoặc xóa hoặc bất kỳ lệnh sửa đổi cơ sở dữ liệu nào khác. Do đó, làm cách nào để tạo ngữ cảnh dữ liệu hoặc thực thể chỉ đọc.


3
Cung cấp cho họ một ngữ cảnh với người dùng không có quyền ghi vào cơ sở dữ liệu.
vcsjones

Cảm ơn. Tôi đang sử dụng cơ sở dữ liệu SQLite. Chỉ cần phát hiện ra rằng nó có thể được mở ở chế độ chỉ đọc thông qua tùy chọn chuỗi kết nối.
Harindaka

2
Đừng cho họ một DbContext, hãy cho họ một IQueryablehoặc nhiều.
ta.speot.is

Câu trả lời:


178

Ngoài việc kết nối với người dùng chỉ đọc, bạn có thể làm một số việc khác với DbContext của mình.

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
rõ ràng bạn là 'người đàn ông bên trong' :) - điều này thú vị hơn rất nhiều so với kết nối 'chỉ đọc'
NSGaga-hầu như không hoạt động

6
Lưu ý rằng việc sử dụng AsNoTracking()sẽ khiến bạn không thể sử dụng lazy loading.
Tom Pažourek

@ TomPažourek Tôi không biết điều đó có đúng không ... Tôi nghĩ EF vẫn tạo proxy tải chậm, nhưng độ phân giải danh tính có thể hơi kỳ lạ.
bricelam

3
Đừng quên ghi đè public override Task<int> SaveChangesAsync().
Pete

7
Đừng dựa vào điều này, bởi vì (context as IObjectContextAdapter).ObjectContext.SaveChanges()nó sẽ vẫn hoạt động. Lựa chọn tốt nhất là sử dụng DbContext(string nameOrConnectionString);contstructor với một chuỗi kết nối đọc / ghi cho nội dung tạo cơ sở dữ liệu và một chuỗi kết nối chỉ đọc sau đó.
Jürgen Steinblock

32

Trái ngược với câu trả lời được chấp nhận, tôi tin rằng sẽ tốt hơn nếu ưu tiên thành phần hơn là thừa kế . Sau đó, sẽ không cần phải giữ các phương thức như SaveChanges để đưa ra một ngoại lệ. Hơn nữa, tại sao bạn cần phải có những phương pháp như vậy ngay từ đầu? Bạn nên thiết kế một lớp theo cách mà người tiêu dùng của nó không bị lừa khi nhìn vào danh sách các phương thức của nó. Giao diện công khai phải phù hợp với mục đích và mục tiêu thực tế của lớp trong khi trong câu trả lời được chấp nhận có SaveChanges không ngụ ý rằng Ngữ cảnh là chỉ đọc.

Ở những nơi mà tôi cần có ngữ cảnh chỉ đọc, chẳng hạn như trong mẫu CQRS bên Đọc , tôi sử dụng cách triển khai sau. Nó không cung cấp bất cứ thứ gì khác ngoài khả năng Truy vấn cho người tiêu dùng.

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

Bằng cách sử dụng ReadOnlyDataContext, bạn có thể chỉ có quyền truy cập vào các khả năng truy vấn của DbContext. Giả sử bạn có một thực thể có tên Order, sau đó bạn sẽ sử dụng cá thể ReadOnlyDataContext theo cách như bên dưới.

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

Phương pháp này có cho phép sử dụng đăng nhập sql chỉ db_datareader không? Với một DBContext tiêu chuẩn, EF ném quyền CREATE TABLE bị từ chối ngay cả khi mã truy vấn của tôi không bao gồm bất kỳ SaveChanges () nào.
reachingnexus

2
Và làm cho nó kế thừa từIDisposable
hkarask

Thay vì sử dụng Đặt <>, tôi đề xuất Truy vấn <>. public IQueryable<TEntity> Get<TEntity>() where TEntity : class { return _dbContext.Query<TEntity>().AsNoTracking(); }
Allan Nielsen,

@hkarask - không chắc tôi sẽ làm điều đó. Vì lệnh gọi này không tạo ra DbContext, nó không nên loại bỏ nó. Điều này có thể dẫn đến một số lỗi khó theo dõi sau này.
Allan Nielsen,

@AllanNielsen Query <> được đánh dấu là không dùng nữa. Theo nó Set <> nên được sử dụng.
Frank
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.