I'm using .net core 2.2 with Entity Framework Code-First, and I create some models with relationships, and all relations working well unless relations with lookup model which are automatically load the related data of the model and the inverse property too
Here is the code:
Company.cs
public class Company
{
public Company()
{
Lookups = new HashSet<Lookup>();
}
public Guid Id { get; set; }
// Relationships
// Address
[ForeignKey("AddressForeignKey")]
public Address Address { get; set; }
// User
[InverseProperty("Company")]
public List<User> UsersInCompany { get; set; }
// Lookup as a country
public Guid? CountryId { get; set; }
public Lookup Country { get; set; }
// Lookup as a bank
public Guid? BankId { get; set; }
public Lookup DefaultBank { get; set; }
// Lookup as a socialInsuranceOffice
public Guid? SocialInsuranceOfficeId { get; set; }
public Lookup DefaultSocialInsuranceOffice { get; set; }
// Lookup as a currency
//[ForeignKey("DefaultCurrencyForeignKey")]
public Guid? CurrencyId { get; set; }
public Lookup Currency { get; set; }
// Lookup for all lookups types
public ICollection<Lookup> Lookups { get; set; }
}
Address.Cs
public class Address
{
public Guid Id { get; set; }
// Relationships
// Company
[InverseProperty("Address")]
public List<Company> Companies { get; set; }
// Lookup as a governorate
[ForeignKey("LookupForeignKey")]
public Lookup GovernorateLookup { get; set; }
}
DataContext.Cs
// Company and Address
modelBuilder.Entity<Company>()
.HasOne(u => u.Address)
.WithMany(r => r.Companies)
.OnDelete(DeleteBehavior.SetNull);
// Address and Lookup
modelBuilder.Entity<Address>()
.HasOne(a => a.GovernorateLookup)
.WithMany(l => l.GovernoratesUserAsAddress)
.OnDelete(DeleteBehavior.SetNull);
modelBuilder.Entity<Company>(com =>
{
// Company and Lookup for defaultCountry
com.HasOne(c => c.Country)
.WithMany(d => d.CompanyCountries)
.HasForeignKey(f => f.CountryId)
.HasConstraintName("COM_COUNTRY_FK")
.OnDelete(DeleteBehavior.Restrict);
// Company and Lookup for defaultBank
com.HasOne(c => c.DefaultBank)
.WithMany(d => d.CompanyBanks)
.HasForeignKey(f => f.BankId)
.HasConstraintName("COM_BANK_FK")
.OnDelete(DeleteBehavior.Restrict);
// Company and Lookup for defaultSocialInsuranceOffice
com.HasOne(c => c.DefaultSocialInsuranceOffice)
.WithMany(d => d.CompanySocialInsuranceOffices)
.HasForeignKey(f => f.SocialInsuranceOfficeId)
.HasConstraintName("COM_SOCIALINSURANCEOFFICE_FK")
.OnDelete(DeleteBehavior.Restrict);
// Company and Lookup for currency
com.HasOne(c => c.Currency)
.WithMany(d => d.CompanyCurrencies)
.HasForeignKey(f => f.CurrencyId)
.HasConstraintName("COM_CURRENCY_FK")
.OnDelete(DeleteBehavior.Restrict);
// Company and Lookup for all Lookups types
com.HasMany(c => c.Lookups)
.WithOne(d => d.Company)
.HasForeignKey(f => f.CompanyId)
.HasConstraintName("COM_ALL_LOOKUPS_FK")
.OnDelete(DeleteBehavior.Cascade);
});
Please note that all relations are working well but only the relation with lookup "I have 5 relation with the same table lookup" load all data and inverse automatically, and I need to know why this is happening and how can I stop it.
Thanks in advance.
You're question is difficult to understand, but I believe the "issue" here is EF's object fixup. I quote "issue", because this is actually a feature.
EF has an object cache. Whenever you query anything, the instances created are stored in that object cache, allowing future queries for the same instances to be pulled from that cache, rather than having to roundtrip to the database again.
When it comes to relationships, if EF has the related entities already in its object cache, it performs a "fixup", where it adds the related instances automatically to the navigation property. Again, this is an optimization feature, as now you do not need to issue another query to retrieve those.
The only way around this is to use AsNoTracking
when you query. For example:
var companies = await _context.Companies.AsNoTracking().ToListAsync();
With AsNoTracking
, EF will not maintain the object cache and it will also not perform change tracking on those entities. That last part is important, because you then need to be very careful if you attempt to modify these entities in any way, as EF will not be aware of them until you explicitly attach them. However, if you're just performing reads, using AsNoTracking
is actually more performant anyways.