Entity Framework table splitting - how to initialize lazy-loaded properties?

503 Views Asked by At

Using Entity Framework 6.0, I am attempting to implement table splitting to improve query performance on tables with columns that contain BLOB data. I have followed the recommendations in this tutorial and it does indeed work as described.

Here's a very simplified example of the entity classes that map to one of my split tables ...

public class MyEntity
{
    public string Id { get; set; }      

    public virtual MyEntityContent Content { get; set; }

    public string Name { get; set; }
}

public class MyEntityContent
{
    public string Id { get; set; }      

    public virtual MyEntity Entity { get; set; }

    public byte[] Blob { get; set; }
}

... and the corresponding configuration code in the associated DbContext implementation ...

modelBuilder.Entity<MyEntity>().HasKey(e => e.Id).ToTable("MyEntities");
modelBuilder.Entity<MyEntityContent>().HasKey(c => c.Id).ToTable("MyEntities");
modelBuilder.Entity<MyEntity>().HasRequired(e => e.Content).WithRequiredPrincipal(d => d.Entity);

Given that the lazy-loaded Content property is Required by Entity Framework, it seems sensible to initialize it to a default value in the constructor of the containing MyEntity class ...

public MyEntity()
{
    Content = new MyEntityContent();                
}

... which enables a new instance of the class to be created and partially populated, without the risk of an exception being thrown by forgetting to initialize the required property value:

var entity = new MyEntity {Id = "XXX", Name = "something"};

I typically use a similar technique to initialize collection properties on EF entities and it works fine. However, in the above scenario, this initialization in the constructor has an unexpected effect: when retrieving existing entity instances from the database, the database value in the lazy-loaded property is ignored in favor of the empty default value.

This seems illogical to me. Doesn't Entity Framework create an entity object by first calling its default constructor and then applying its own property values to the created instance? If so, this should overwrite my default Content property value with a new instance of MyEntityContent, based on database data. This is how it seems to work with lazy-loaded collection properties.

If it's not possible to do this in the way I am expecting, is there an alternative technique for initializing lazy-loaded properties?

1

There are 1 best solutions below

0
On

Don't initialize virtual members and perhaps, if you have to, handle any exceptions from uninitialized members.

I just had this issue with an entity with two virtual fields. Originally I had it initialize those two, but after removing them (and initializing the other fields to some default value), it started working for me. Try it out and let me know!

[Edit] I just realized I replied this to a slightly old post, didn't see the date. I guess I'll leave this answer here in case.