实体框架(Entity Framework):何时使用Set<>?

16

我正在尝试理解 Entity Framework 的基础知识,并且有一个关于 DbContext 上的 Set<> 方法的问题。在下面的问题中,我使用的是数据库优先模型。

假设我有一个 ActivityLog 数据库,其中包括一条消息(例如 NLog 消息),我可以编写一些代码来提取所有消息,如下所示:

using (var entities = new ActivityLogEntities())
    foreach (var log in entities.AcitivityLogs)
        Console.WriteLine(log.Message);

然而,我也可以通过这样做来实现同样的效果:

using (var entities = new ActivityLogEntities())
    foreach (var message in entities.Set<ActivityLog>().Select(entity => entity.Message))
        Console.WriteLine(message);

我的问题是这两个陈述之间有什么区别?何时更适合使用其中之一?或者这只是个人喜好的问题?


1
如果您没有ActivityLogs属性,则无法使用ActivityLogs属性。这似乎是一个无用的回答,但我曾经遇到过这样的情况:我需要访问一个类型的DbSet<T>,而该类型故意没有直接的实体属性。但这并没有回答当两者都可能时应该使用哪个的问题。 - user743382
@hvd同意,但是在上下文中没有引用类型是非常罕见的(而且这并不是完全微不足道的事情)。 - undefined
@LukeMcGregor 考虑以下代码 public class Order { public ICollection<OrderLine> Lines { get; set; } } public class OrderLine { } public class Context { public IDbSet<Order> Orders { get; private set; } }。不需要进行额外的工作就可以使其正常工作,而且通常情况下在没有订单的情况下访问OrderLines也没有意义,那么为什么我要在上下文层面添加一个OrderLines属性呢? - user743382
3个回答

15

没有显著的区别。在第一种情况下,你会得到类似这样的东西:

class MyContext : DbContext
{
    public DbSet<AcitivityLog> AcitivityLogs { get; set; }
}

当创建上下文时,它会查找公共的DbSet<T>读/写属性,并执行以下伪代码:

创建上下文时,会查找公共的DbSet<T>读写属性,并执行以下伪代码:

dbSetProperty = Set<EntityType>();

但是有些情况下,您可能会:

  1. 不想公开所有实体类型的公共属性;
  2. 在上下文的设计时间不知道所有实体类型。

在这些情况下,Set<T> 是获取正确实体集的唯一方法。


在你的第二个例子中,我猜想这只适用于自动生成的内容? - Serberuss
@Serberuss:不仅如此。DbContext API的好处之一是您可以动态构建上下文(与使用ObjectContex和EDM设计器的传统方法相反)。这使得数据模型更加灵活,但它也带来了一个副作用:实体类型列表并非静态的,因此DbContext祖先的开发人员无法知道每个实体类型。 - Dennis
不幸的是,第二个示例无法正常工作。我遇到了以下错误: “<type>实体不是当前上下文模型的一部分。” 我不知道我做错了什么。 - krypru

11
我曾经使用Set<T>的唯一原因是在处理未知类型时,例如通用插入。

这里有一个来自我的通用存储库的示例:

  public void AddOnSave(T entity)
  {
     ctx.Set<T>.Add(entity);
  }

在我看来,将其用于常规事务只会使代码变得不易读。


AddOrUpdate 是指向数据库中添加或更新实体的方法。它可以根据实体的主键判断该实体是否已存在于数据库中,如果存在,则更新现有实体,否则将其添加到数据库中。 - oCcSking
@oCcSking 不确定你的意思是什么? - undefined
实际上,我没有正确理解你的回答,对于你不确定是添加还是更新的情况感到困惑,那么你可以使用AddOrUpdate。 - oCcSking
1
@oCcSking 哦,是的,这不是添加或更新,而是处理类型为T的通用存储库的添加方法。 - undefined

3
如果您查看生成的DbContext类,您会发现AcitivityLogs只是一个DbSet<ActivityLog>
所以它们是一样的东西。这只是您的DbSet的类型定义。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接