排除相关实体,即使DbContext已经加载了它们
本文关键字:加载 DbContext 实体 即使 排除 | 更新日期: 2023-09-27 18:03:12
是否有一种方法可以获得EntityA
的列表,而无需其相关导航,即使DbContext拥有它们。我需要这个用于序列化。
我试图关闭Lazy loading
并显式地.Include
任何相关实体。但是如果DbContext已经加载了它们,它还是会被包含。
场景是这样的:
public class LookupRepository : ILookupRepository
{
private readonly CustomDbContext _dbContext;
public LookupRepository(CustomDbContext dbContext) {
if(dbContext == null)
throw new ArgumentNullException("dbContext");
_dbContext = dbContext;
}
public IEnumerable<Country> GetCountriesFull() {
return _dbContext.Set<Country>()
.Include(c => c.Areas)
.Include(c => c.Continent)
.ToList();
}
public IEnumerable<Country> GetCountries() {
return _dbContext.Set<Country>()
.ToList();
}
public IEnumerable<Continent> GetContinents() {
return _dbContext.Set<Continent>()
.ToList();
}
public IEnumerable<Area> GetAreas() {
return _dbContext.Set<Area>()
.ToList();
}
}
我注入的DbContext是这样初始化的
public CustomDbContext CreateDbContext(){
var dbContext = new CustomDbContext();
dbContext.Configuration.ProxyCreationEnabled = false;
return dbContext;
}
所以这个使用干净DbContext 的测试通过了:
[Test]
public void GetCountries_CalledOnce_ReturnsCountriesWithoutNavigations() {
var sut = CreateLookupRepository();
var countries = sut.GetCountries();
CollectionAssert.IsNotEmpty(countries);
Assert.That(countries.Select(c => c.Continent), Is.All.Null);
Assert.That(countries.Select(c => c.Areas), Is.All.Null);
}
但是这个包含所有对GetCountriesFull
的调用失败:
[Test]
public void GetCountries_AfterCallingGetCountriesFull_StillReturnsNoNavigations() {
var sut = CreateLookupRepository();
var fullCountries = sut.GetCountriesFull();
var countries = sut.GetCountries();
CollectionAssert.IsNotEmpty(countries);
Assert.That(countries.Select(c => c.Continent), Is.All.Null);
Assert.That(countries.Select(c => c.Areas), Is.All.Null);
}
有什么建议吗?我想使用工厂为每个方法创建一个新的dbContext(无论如何,此代码仅在我的应用程序启动时运行,数据作为Singleton保留在内存中),但我认为必须有一个更好的解决方案。
最简单的方法是使用AsNoTracking()
获取实体。通过这样做,您告诉EF不要将实体添加到其内部缓存中,并且实体关系将不会被解析。
但是这里(再次)额外的存储库层对您不利,因为您不能只执行像
这样的调用var fullCountries = sut.GetCountriesFull().AsNoTracking();
您必须进行重载,或者添加像bool withTracking
这样的参数,或者初始化存储库,选择始终(或从不)使用AsNoTracking()
。
如果你不关心它们是否被不必要地加载(或者它们因为其他原因已经被填充),如果你不想让它们被传递,只需将所有导航属性设置为null
。
您还可以将[XmlIgnore]
属性添加到导航属性中,这样序列化器就不会包含它们。这也可以防止同样的问题。
亲爱的,有很多方法可以做到1)如果你首先使用代码,那么遵循这个
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
base.Configuration.LazyLoadingEnabled = false;
}
2) edmx文件在and定义中有一个延迟加载属性,您可以将延迟加载设置为false:
public MyEntitiesContext() : base("name=MyEntitiesContext", "MyEntitiesContext")
{
this.ContextOptions.LazyLoadingEnabled = false;
OnContextCreated();
}
或者直接这样做
public BlogContext() : base()
{
this.Configuration.LazyLoadingEnabled = false;
}