即使DbContext已加载它们,也要排除相关实体

时间:2014-05-14 10:35:43

标签: c# entity-framework

有没有一种方法可以获得EntityA的列表而没有相关的导航,即使DbContext有它们也是如此。我需要这个用于序列化。

我尝试关闭Lazy loading并明确.Include任何相关实体。但是如果DbContext已经加载了它们,那么无论如何都会包含它。

Senario是这样的:

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保留在内存中),但我认为必须有一个更好的解决方案

3 个答案:

答案 0 :(得分:2)

最简单的方法是使用AsNoTracking()获取实体。通过这样做,您告诉EF不要将实体添加到其内部缓存中,并且不会解析实体关系。

但是这里(再次)额外的存储库层对你不利,因为你不能只做一个像

这样的调用
var fullCountries = sut.GetCountriesFull().AsNoTracking();

您必须进行重载,或添加bool withTracking之类的参数,或者使用选项初始化存储库以始终(或从不)使用AsNoTracking()

答案 1 :(得分:1)

如果您不在乎不必要地加载它们(或者由于其他原因已经填写了它们),只需将所有导航属性设置为null,如果您不希望它们通过了。

您还可以将[XmlIgnore]属性添加到导航属性中,这样序列化程序就不会包含它们。这也可以防止同样的问题。

答案 2 :(得分:-1)

亲爱的,有很多方法可以做到这一点 1)如果您使用的是代码,请按照

进行操作
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
 base.Configuration.LazyLoadingEnabled = false;
}

2)edmx文件在和定义中有一个延迟加载属性,你可以将延迟加载设置为false:

public MyEntitiesContext() : base("name=MyEntitiesContext", "MyEntitiesContext")
{
this.ContextOptions.LazyLoadingEnabled = false;
OnContextCreated();
}

或只是这样做

public BlogContext() : base()
{
this.Configuration.LazyLoadingEnabled = false;
}