排除相关实体,即使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保留在内存中),但我认为必须有一个更好的解决方案。

排除相关实体,即使DbContext已经加载了它们

最简单的方法是使用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;
}