zafeiris.m
zafeiris.m

Reputation: 4489

Exclude related entities even if DbContext has loaded them

Is there a way I can get a list of EntityA without its related navigations, even when DbContext has them. I need this for serialization purposes.

I tried to turn Lazy loading off and explicitly .Include any related entities. But if DbContext has already loaded them, it will be included anyway.

The senario is like this:

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();
    }       
}

And the DbContext I inject in there is initialized like this:

public CustomDbContext CreateDbContext(){
    var dbContext = new CustomDbContext();
    dbContext.Configuration.ProxyCreationEnabled = false;
    return dbContext;
}

So this test that uses a clean DbContext passes:

[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);
}

but this one that includes all a call to GetCountriesFull fails:

[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);
}

Any advice on how to do this? I thought of using a factory to create a new dbContext for each method (anyway this code is only run on my application startup and data remain in memory as Singleton), but I thought there must me a better solution.

Upvotes: 2

Views: 3352

Answers (3)

Gert Arnold
Gert Arnold

Reputation: 109137

The most simple way to do this is by getting the entities with AsNoTracking(). By doing this, you tell EF not to add the entities to its internal cache and entity relationships will not be resolved.

But here (again) the extra repository layer works against you, because you can't just do a call like

var fullCountries = sut.GetCountriesFull().AsNoTracking();

You have to make overloads, or add parameters like bool withTracking, or initialize the repository with an option to always (or never) use AsNoTracking().

Upvotes: 2

Developerzzz
Developerzzz

Reputation: 1126

Dear there are many ways to doing it 1)if you are using code 1st then follow this

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

2)The edmx file has in the and definition an attribute for lazy loading where you can set lazy loading generally to false:

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

or simply do this

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

Upvotes: -2

Flater
Flater

Reputation: 13783

If you don't care that they are being loaded unnecessarily (or they were already filled in for another reason), just set all navigational properties to null if you don't want them to be passed.

You can also add the [XmlIgnore] attribute to your navigational properties, so the serializer will not include them. That also prevents the same issue.

Upvotes: 1

Related Questions