定义DbSet

DbContext 使用DbSet 属性

Code First 示例中显示的常见情况是让 DbContext 为模型实体类型使用公共自动 DbSet 属性。例如:

public class  BloggingContext: DbContext

{

  public DbSet<Blog>Blogs { get; set;}

  public DbSet<Post>Posts { get; set;}

}

在 CodeFirst 模式下使用时,这会将 Unicorn、Princess、LadyInWaiting 和Castle 配置为实体类型,也将配置可从这些类型访问的其他类型。此外,DbContext 还将自动对其中每个属性调用 setter 以设置相应 DbSet 的实例。

DbContext 使用IDbSet 属性

在创建 mock或 fake 等情况下,更适合使用接口来声明 set 属性。在这些情况下,可使用 IDbSet 接口替代 DbSet。例如:

public class  BloggingContext: DbContext

{

  public IDbSet<Blog>Blogs { get; set;}

  public IDbSet<Post>Posts { get; set;}

}

此上下文的工作方式与对其 set 属性使用DbSet 类的上下文完全相同。

DbContext 使用只读set 属性

如果不希望为DbSet 或 IDbSet 属性公开公共 setter,可以改为创建只读属性并自建 set 实例。例如:

public class  BloggingContext: DbContext

{

  public DbSet<Blog>Blogs

  {

    get { return Set<Blog>();}

  }

 

  public DbSet<Post>Posts

  {

    get { return Set<Post>();}

  }

}

请注意,DbContext将缓存从 Set 方法返回的 DbSet 实例,以便每次调用其中每个属性时都返回同一实例。

搜索 CodeFirst 实体类型的工作方式与搜索具有公共 getter 和setter 的属性相同。

DbContext使用注意事项

· 随着越来越多的对象和他们的引用进入内存,DbContext的内存消耗可能会迅速增长,这将会引起性能问题。

· 当不再使用context对象的时候,一定要释放它。

· 如果一个异常使得context进入了一个不可恢复的状态,整个应用可能会终止。

· 长时间使用的context会增加并发冲突的可能。

DbSet使用注意事项

DbSet总是针对数据库执行查询,即使要查询的数据已经在上下文中,下面几种情况下会执行数据库查询。

· 执行foreach

· 调用ToArray, ToDictionary, ToList.

· 在最外层查询调用LINQ操作符First,Any等等。

· DbSet的扩展方法Load,DbEntityEntry.Reload,Database.ExecuteSqlCommand.

当数据库返回查询结果的时候,如果结果集中的对象在context中不存在,那么就会将对象attach到上下文中。如果对象已经存在(根据id来判断),那么就会返回在上下文中已经存在的对象,数据库的值不会覆盖当前对象database values。在这种情况下,如果我们长时间持有DbContext,那么我们在每次查询的时候得到就很有可能不是最新版本的对象。

在执行一个查询的时候,上下文中新添加但是还没有保存的对象不会作为查询结果返回,如果想访问这些对象,需要访问Local属性。下面是关于local属性的备注

1. Local属性不只是包含新添加的对象,它包含所有已经加载到context中的对象。

2. Local属性不包含那些已经被Remove的对象(上下文中remove了,但是还在数据库中)

3. 查询结果永远反应数据库的真实数据,在上下文中被Remove了但是还没有在数据库删除的对象,仍然可以查询到。DbContext.ChangeTracker属性提供了DbChangeTracker的实例,该实例的Entries属性返回一个DbEntityEntry集合,可以找到所有当前上下文中跟踪的实体及其状态信息。

有时候在查询大量实体并只进行只读操作的时候,实体跟踪是没有任何意义的,禁用实体跟踪会提高查询性能,可以AsNoTracking方法来禁用实体跟踪,例如:

using(var context = newBloggingContext())
{

  // Query for allblogs without tracking them

  var blogs1 =context.Blogs.AsNoTracking();

 

  // Query for someblogs without tracking them

  var blogs2 =context.Blogs

                      .Where(b =>b.Name.Contains(".NET"))

                      .AsNoTracking()

                      .ToList();

}

根据主键查找实体

DbSet.Find方法会根据主键来查找被上下文跟踪的实体。如果上下文中不存在此对象,那么将会对数据库进行查询来查找实体,如果没有找到实体,则返回null。Find方法可以查询到刚刚添加到上下文但是还没有被保存到数据库的实体,这与LINQ查询不同。

使用 Find 方法时必须考虑:

1. 如果对象没有在缓存中,则 Find 没有优势,但语法仍比按键进行查询简单。

2. 如果启用自动检测更改,则根据模型的复杂性以及对象缓存中的实体数量,Find 方法的成本可能会增加一个数量级,甚至更多。

此外,请注意Find 仅返回要查找的实体,它不会自动加载未在对象缓存中的关联实体。如果需要检索关联实体,可通过预先加载使用按键查询。