Har*_*aka 103 .net datacontext entity-framework readonly entity-framework-4
我需要向第三方插件公开实体框架数据上下文.目的是允许这些插件仅获取数据,而不是让它们发出插入,更新或删除或任何其他数据库修改命令.因此,我如何只读取数据上下文或实体.
bri*_*lam 166
除了与只读用户连接外,还可以对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>();
}
}
Run Code Online (Sandbox Code Playgroud)
Ehs*_*edi 16
与公认的答案相反,我相信最好是继承而不是继承。这样就无需保留诸如SaveChanges之类的方法来引发异常。此外,为什么首先需要使用这种方法?您应该以一种让其使用者在查看其方法列表时不会上当的方式设计类。公共接口应与类的实际意图和目标保持一致,而在接受的答案中,具有SaveChanges并不意味着Context是只读的。
在需要具有只读上下文的地方,例如CQRS模式的“读取”端,我使用以下实现。除了向使用者提供查询功能外,它没有提供任何其他功能。
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();
}
public void Dispose()
{
_dbContext.Dispose();
}
}
Run Code Online (Sandbox Code Playgroud)
通过使用ReadOnlyDataContext,您只能访问DbContext的查询功能。假设您有一个名为Order的实体,那么您将以如下方式使用ReadOnlyDataContext实例。
readOnlyDataContext.Set<Order>().Where(q=> q.Status==OrderStatus.Delivered).ToArray();
Run Code Online (Sandbox Code Playgroud)
小智 7
在我使用 EF Core/.NET 5.0 的场景中,我希望 SaveChanges 具有编译时安全性。这只适用于“新”而不是“覆盖”。
我并排使用读/写和只读上下文,其中一个上下文继承另一个上下文,因为附加了很多表。这就是我使用的,“ContextData”是我原来的 R/W DbContext:
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.");
}
}
Run Code Online (Sandbox Code Playgroud)
注意:
在覆盖继承的 SaveChanges*() 时,我必须使用“new”而不是“override”,以便出现警告/错误。使用“覆盖”,根本没有编译时错误/警告。
使用“override”你会得到CS0809 [1],但使用“new”则不会
使用“new”仅适用于类本身,但不适用于父类的上下文:
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
Run Code Online (Sandbox Code Playgroud)
SaveChanges 和 SaveChangesAsync 的变体需要正确选择(可选)参数。(这是针对.NET 5.0的,我没有检查它是否与其他版本的EF Core/EF不同)
结论
==> 没有灵丹妙药,选择取决于品味和环境......
[1] https://learn.microsoft.com/en-us/dotnet/csharp/misc/cs0809?f1url=%3FappId%3Droslyn%26k%3Dk(CS0809)
归档时间: |
|
查看次数: |
37467 次 |
最近记录: |