Reputation: 4489
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
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
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
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