C# · 12月 27, 2021

c# – 是DbSet <>.本地的东西要特别小心使用?

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

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

那就是问题的出现.我的存储库依赖于DbSet< TEntity>类与Linq2sql(Include()导航属性相似).但是,DbSet< TEntity>不包含处于“已添加”状态的实体.

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

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

ChangeTracker似乎需要一些额外的努力才能使其工作,使我可以使用Linq2sql来包含()导航属性,例如

DbSet< TEntity>.本质似乎对我来说有点怪异.它可能只是这个名字.我只是读一些它不能很好地执行(比DbSet本身慢)的东西.不确定是否是虚假陈述.

有些具有重要实体框架经验的人可以在这上亮一点吗?什么是“明智”的路径呢?或者我看到鬼,我应该总是使用.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<TEntity> // instead of the DbSet<TEntity>.Local. Assert.IsNotNull(tenant); // Can I safely use DbSet<TEntity>.Local ? Or should I play // around with DbContext.ChangeTracker instead? }

我如何使用我的存储库的一个例子

在我的存储库我有这个方法:

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

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

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

这主要是为什么我更喜欢坚持DbSet的变量.我需要灵活地包括导航属性.如果我使用ChangeTracker,我检索列表中的实体,这不允许我在稍后的时间点延迟加载相关实体.

如果这是接近难以理解的斗牛士,那么请让我知道,以便我可以改善这个问题.我迫切需要一个答案.

Thx提前很多!

解决方法 如果您想要轻松地对DbSet发出查询,并找到新创建的项目,那么在创建每个实体后,您将需要调用SaveChanges().如果您使用“工作单位”风格的方法来处理持久化实体,这其实并没有问题,因为您可以将工作单元包含在UoW中的所有操作作为DB事务(即,当UoW创建新的TransactionScope被创建,并在UoW完成时调用Commit()).使用此结构,更改将发送到DB,并且将对DbSet可见,但对其他UoW(对任何使用的隔离级别模数)都不可见.

如果你不想要这个开销,那么你需要修改你的代码,以便在适当的时候使用Local(可能涉及到Local,然后在DbSet发出一个查询,如果你没有找到你的正在寻找).在这些情况下,DbSet上的Find()方法也是非常有用的.它将通过主键在本地或数据库中找到一个实体.所以如果你只需要通过主键找到项目,这样很方便(也有性能优势).