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>();
}
}
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 实例。
public IQueryable<MyFirstThing> MyFirstHandPickThings => this.dbContext.Set<MyFirstThing>().AsNoTracking();
public IQueryable<MySecondThing> MySecondHandPickThings => this.dbContext.Set<MySecondThing>().AsNoTracking();
public class ContextDataReadOnly : ContextData
{
public ContextDataReadOnly() : base()
{
ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
}
[Obsolete("This context is read-only", true)]
public new int SaveChanges()
{
throw new InvalidOperationException("This context is read-only.");
}
[Obsolete("This context is read-only", true)]
public new int SaveChanges(bool acceptAll)
{
throw new InvalidOperationException("This context is read-only.");
}
[Obsolete("This context is read-only", true)]
public new Task<int> SaveChangesAsync(CancellationToken token = default)
{
throw new InvalidOperationException("This context is read-only.");
}
[Obsolete("This context is read-only", true)]
public new Task<int> SaveChangesAsync(bool acceptAll, CancellationToken token = default)
{
throw new InvalidOperationException("This context is read-only.");
}
}
Base b = new Derived();
Derived d = new Derived();
b.SaveChanges(); // Calls Base.SaveChanges, will compile and run without exception
d.SaveChanges(); // Calls Derived.SaveChanges, will not compile
对于 SaveChanges 和 SaveChangesAsync 的变体,需要正确选择(可选)参数。(这是为了。NET 5.0,我还没有检查它是否与其他版本的 EF Core/EF 有所不同)
public interface IReadOnlyContext : IDisposable
{
IQueryable<Customer> Customers { get; }
}
public class ReadOnlyContext : Context, IReadOnlyContext
{
public new IQueryable<Customer> Customers => base.Customers.AsQueryable();
public ReadOnlyContext(DbContextOptions options)
: base(options)
{
}
[Obsolete("This context is read-only", true)]
public new int SaveChanges()
{
throw new InvalidOperationException("This context is read-only.");
}
[Obsolete("This context is read-only", true)]
public new int SaveChanges(bool acceptAll)
{
throw new InvalidOperationException("This context is read-only.");
}
[Obsolete("This context is read-only", true)]
public new Task<int> SaveChangesAsync(CancellationToken token = default)
{
throw new InvalidOperationException("This context is read-only.");
}
[Obsolete("This context is read-only", true)]
public new Task<int> SaveChangesAsync(bool acceptAll, CancellationToken token = default)
{
throw new InvalidOperationException("This context is read-only.");
}
}