Reputation: 128
Been stuck for hours with this weird problem. For some reason entity framework wont load the navigation properties of this 1 to many relationship, even though the generated SQL seems to be right, foreign key exists from SubItems to FrontPageItems:
CONSTRAINT [FK_dbo.SubItems_dbo.FrontPageItems_FrontPageItemId]
FOREIGN KEY ([FrontPageItemId])
REFERENCES [dbo].[FrontPageItems] ([Id]) ON DELETE CASCADE
I have tried loading all frontpageitems with:
_repo.Get();
, but even though the SubItem
table contains foreign keys referencing to FronPageItems
table, no navigation properties gets loaded.
public class FrontPageItem : Logger, IEntity, IIsPublished
{
public FrontPageItem()
{
SubItems = new HashSet<SubItem>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool IsPublished { get; set; }
public virtual ICollection<SubItem> SubItems { get; set; }
}
public class SubItem : Logger, IEntity, IIsPublished
{
public SubItem()
{
FrontPageItem = new FrontPageItem();
}
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string YoutubeUrl { get; set; }
public virtual FrontPageItem FrontPageItem { get; set; }
public int FrontPageItemId { get; set; }
public bool IsPublished { get; set; }
}
public class SampleContext : IdentityDbContext<ApplicationUser>
{
// throwIfV1Schema is used when upgrading Identity in a database from 1 to 2.
// It's a one time thing and can be safely removed.
public SampleContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public static SampleContext Create()
{
return new SampleContext();
}
// Define you conceptual model here. Entity Framework will include these types and all their references.
public IDbSet<FrontPageItem> FrontPageItem { get; set; }
public IDbSet<SubItem> SubItems { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// The DateTime type in .NET has the same range and precision as datetime2 in SQL Server.
// Configure DateTime type to use SQL server datetime2 instead.
modelBuilder.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));
base.OnModelCreating(modelBuilder);
}
}
Btw it works if I remove the foreignkey property in SubItem:
public int FrontPageItemId { get; set; }
I have tried eager loading with include like this:
var frontPageItems = _repo.AsQueryable().Include(o => o.SubItems).ToList();
Upvotes: 0
Views: 2612
Reputation: 128
public SubItem()
{
FrontPageItem = new FrontPageItem();
}
Was the problem. For some reason the constructor in SubItem was created this weird behavour, everything else was fine.
Upvotes: 0
Reputation: 933
LazyLoadingEnabled
must be true, not false:
context.Configuration.LazyLoadingEnabled = true
;
true is the default if you don't set LazyLoadingEnabled at all.
And the SubItems
property must be virtual to enable lazy loading for this property.
Or you can include the property directly in the query.
You also need to set the FK
by using the modelBuilder
modelBuilder.Entity<SubItem>()
.HasRequired(t => t.FrontPageItem)
.WithMany(t => t.SubItems)
.HasForeignKey(d => d.FrontPageItemId)
.WillCascadeOnDelete(true);
Or by configuring Relationships using attributes
[ForeignKey("FrontPageItem")]
public virtual FrontPageItem FrontPageItem { get; set; }
Upvotes: 1
Reputation: 2497
As DavidG mentioned, lazy loading is the default en EF. that means the properties only get loaded once you actually use them.
In order force inclusion of subitems you can use include like this
FrontPageItem.Include(x => x.SubItems).FirstOrDefault().
FrontPageItem here is your dbset. If you query it like this it will load the first frontpageitem with all subitems connected to it.
Update: If you follow the conventions stricktly you won't need to do this but if you have different names for your properties or want to have an explicit foreign key then you can configure the foreign key like this
modelBuilder.Entity<SubItem>()
.HasRequired(t => t.FrontPageItem)
.WithMany(t => t.SubItems)
.HasForeignKey(d => d.FrontPageItemId)
.WillCascadeOnDelete(true);
Upvotes: 2