是DbSet 。本地使用的东西需要特别小心吗?

几天来,我一直在努力从存储库( DbContext )中检索我的实体。

我试图在primefaces动作中保存所有实体。 因此,不同的实体一起代表了对我有价值的东西。 如果所有实体都是“有效”,那么我可以将它们全部保存到数据库中。 实体“a”已存储在我的存储库中,需要检索以“validation”实体“b”。

这就是问题出现的地方。 我的存储库依赖于DbSet类,它与Linq2Sql( Include()导航属性(例如))配合使用。 但是, DbSet不包含处于“已添加”状态的实体。

所以我(据我所知)有两个选择:

  • 使用ChangeTracker查看哪些实体可用,并根据其EntityState将它们查询到一个集合中。
  • 使用DbSet.Local属性。

ChangeTracker似乎需要一些额外的努力来让它以某种方式工作,以便我可以使用Linq2Sql来Include()导航属性,例如

DbSet.Local对我来说似乎DbSet.Local 。 它可能只是名字。 我只是读了一些表现不佳的东西(比DbSet 本身慢)。 不确定这是否是虚假陈述。

具有重要EntityFramework经验的人能否对此有所了解? 什么是“明智”的道路? 或者我看到了幽灵,我应该总是使用.Local属性吗?

使用代码示例更新


出了什么问题的一个例子

  public void AddAndRetrieveUncommittedTenant() { _tenantRepository = new TenantRepository(new TenantApplicationTestContext()); const string tenantName = "testtenant"; // Create the tenant, but not call `SaveChanges` yet until all entities are validated _tenantRepository.Create(tenantName); // // Some other code // var tenant = _tenantRepository.GetTenants().FirstOrDefault(entity => entity.Name.Equals(tenantName)); // The tenant will be null, because I did not call save changes yet, // and the implementation of the Repository uses a DbSet // instead of the DbSet.Local. Assert.IsNotNull(tenant); // Can I safely use DbSet.Local ? Or should I play // around with DbContext.ChangeTracker instead? } 

我想如何使用我的Repository一个例子

在我的Repository我有这个方法:

  public IQueryable GetAll() { return Context.Set().AsQueryable(); } 

我以这种方式在业务代码中使用它:

  public List GetCasesForUser(User user) { return _repository.GetAll(). Where(@case => @case.Owner.EmailAddress.Equals(user.EmailAddress)). Include(@case => @case.Type). Include(@case => @case.Owner). ToList(); } 

这主要是我更喜欢像变量一样坚持DbSet的原因。 我需要灵活地Include导航属性。 如果我使用ChangeTracker我会检索List的实体,这不允许我在稍后的时间点延迟加载相关实体。

如果这接近难以理解的崩溃* t,那么请告诉我,以便我可以改进这个问题。 我迫切需要一个答案。

很多提前!

如果您希望能够“轻松”对DbSet发出查询并让它找到新创建的项目,那么您需要在创建每个实体后调用SaveChanges()。 如果您使用“工作单元”样式方法来处理持久性实体,这实际上没有问题,因为您可以让工作单元将UoW中的所有操作包装为DB事务(即,当UoW创建新的TransactionScope时创建,并在UoW完成时调用Commit())。 使用此结构,更改将发送到DB,并且对DbSet可见,但对其他UoW不可见(以您使用的任何隔离级别为模)。

如果你不想要这个开销,那么你需要修改你的代码以在适当的时候使用Local(这可能涉及查看Local,然后如果你没找到你的话就发出一个针对DbSet的查询正在寻找)。 在这些情况下,DbSet上的Find()方法也非常有用。 它将在Local或DB中按主键查找实体。 因此,如果您只需要通过主键查找项目,这非常方便(并且还具有性能优势)。

正如Terry Coatta所提到的,如果你不想先保存记录,最好的办法是检查两个来源。

例如:

 public Person LookupPerson(string emailAddress, DateTime effectiveDate) { Expression> criteria = p => p.EmailAddress == emailAddress && p.EffectiveDate == effectiveDate; return LookupPerson(_context.ObjectSet.Local.AsQueryable(), criteria) ?? // Search local LookupPerson(_context.ObjectSet.AsQueryable(), criteria); // Search database } private Person LookupPerson(IQueryable source, Expression> predicate) { return source.FirstOrDefault(predicate); } 

对于那些追随者,我遇到了一些类似的问题,并决定尝试.Concat方法。 我没有进行过广泛的性能测试,所以有了比我更多的知识的人应该随意加入。

本质上,为了将function正确地分解成更小的块,我最终得到了一种情况,其中我有一个方法不知道当前UoW中对同一方法的连续或先前调用。 所以我这样做了:

 var context = new MyDbContextClass(); var emp = context.Employees.Concat(context.Employees.Local).FirstOrDefault(e => e.Name.Contains("some name"));