鉴于这种情况:
public class FooContext : DbContext
{
public FooContext(DbContextOptions<FooContext> opts) : base(opts)
{ }
public DbSet<Bar> Bars { get; set; }
}
我可以通过两种方式进入Bar
:
fooContext.Bars.Add(new Bar()); // Approach 1
或
fooContext.Set<Bar>().Add(new Bar()); // Approach 2
两种方法有什么区别?
我试图通过以下方式回答自己的问题:
Set<T>()
还会创建一个DbSet<T>
)DbSet<T>
specifically on the docs urls,但似乎没有相关结果DbSet<T>
docs的介绍,它只是建议您可以通过两种方法中的任何一种来获取一套(无论是否存在差异)Set<T>()
docs 但是我找不到关于这两个用于哪个目的的很好的解释。有什么区别?或许更重要的是:我应该在哪里以及如何在文档中找到它?
答案 0 :(得分:3)
他们做的完全一样。真正的问题是,什么时候可以使用另一个。
当您知道要使用的实体类型时,可以使用DbSet。您只需编写DbContext名称,然后输入实体类型名称,然后可以使用可用的实体方法为该实体创建,读取,更新或删除条目。您知道想要什么,知道在哪里做。
当您不知道要使用的实体类型时,可以使用Set。可以说,您想构建一个类,该类执行您的存储库功能,以创建,读取,更新和删除实体的条目。您希望此类可重用,以便您可以在其上传递DbContext,并且它将使用相同的create,read,update和delete方法。您不确定要在哪个DbContext上使用它或DbContext将具有什么DbSet。这是您使用泛型的时间,以便您的类可以被任何DbContext用于任何DbSet。
这是一个类的示例,可用于在任何DbContext中的任何DbSet上创建任何实体
public class Repository<TDbContext> where TDbContext : DbContext
{
private TDbContext _context { get; }
public Repository(TDbContext context)
{
_context = context;
}
public TEntity Create<TEntity>(TEntity entity) where TEntity : class
{
if(entity != null)
{
var dataSet = _context.Set<TEntity>();
if(entity is IEnumerable)
{
dataSet.AddRange(entity);
}
else
{
dataSet.Add(entity);
}
_context.SaveChanges();
}
return entity;
}
}
这是使用方法。
var dbContext01 = new DbContext01();
var dbContext02 = new DbContext02();
var repository01 = new Repository<DbContext01>(dbContext01);
var repository02 = new Repository<DbContext02>(dbContext02);
repository01.Create(new EntityOnDbContext01 {
Property01A = "String",
Property01B = "String"
});
repository02.Create(new EntityOnDbContext02 {
Property02A = 12345,
Property02B = 12345
});
如果您想了解更多有关泛型的信息,请点击这里。非常棒。
https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/
答案 1 :(得分:2)
不幸的是,目前您在官方文档中找不到解释,主要是因为所有这些在功能上都是等效的。
首先,DbConext
的泛型方法(例如Add<TEntity>
,Remove<TEntity>
,Attach<TEntity>
等),与相应的{{1 }}方法(实际上,它们实际上是后者的实现,即DbSet<TEntity>
方法仅调用相应的DbSet
通用方法)。您使用哪一个只是一个品味问题。
第二,DbContext
属性和DbSet<TEntity>
方法在功能上是等效的,但是确实有一些非功能上的差异。
Set<TEntity>
属性在上下文创建时被填充一次,而DbSet
方法始终执行查找,因此Set
属性访问应比DbSet
方法更快(尽管不重要)。
重要的区别实际上是EF Core Including & Excluding Types约定:
按照惯例,模型中包括在您的上下文的
Set
属性中公开的类型。此外,还包括DbSet
方法中提到的类型。
因此,尽管您可以保留OnModelCreating
而不暴露DbContext
属性,并且仅使用DbSet
方法工作,但是如果这样做,则必须明确地告诉EF Core哪些是您的实体类型,在每种实体类型的Set
中添加对OnModelCreating
的调用(这就是文档在modelBuilder.Entity<TEntity>();
方法中提到的类型的含义)。 / p>
答案 2 :(得分:0)
它们是相同的,并且实际上返回相同的DbSet
实例。
var options = //...;
using (var ctx = new FooContext(options))
{
// true
bool isSame = ReferenceEquals(ctx.Bars, ctx.Set<Bar>());
}
在您的DbSet
中不包括DbContext
属性的一个用例是,您想向使用者隐藏实体类型。 (例如,充当many-to-many relationship的联接表的实体)。然后,您可以将实体标记为internal class
,这样,消费者也就无法使用Set<>
来访问它。
此外,如果您不公开DbSet
属性,则需要显式配置实体,否则将出现以下异常:
//throws System.InvalidOperationException: 'The entity type 'Foo' was not found. Ensure that the entity type has been added to the model.'
ctx.Set<Foo>().Add(new Foo());