Can I lazy load part of an entity in Entity Framework 6 with Entity Splitting?

2.9k views Asked by At

I am quite new to Entity Framework, and while it has many advantages over NHibernate, I am disappointed to discover it does not support lazy loading of properties.

Take this class:

public class Product
{ 
    public virtual Guid Id {get;set;}
    public virtual string Name {get;set;}
    public virtual string Details {get;set;}
}

My plan was to use Entity Splitting to map it to two tables:

CREATE TABLE [dbo].[Product](
[Id] [uniqueidentifier] NOT NULL PRIMARY KEY,
[Name] [nvarchar](50) NULL
) 

CREATE TABLE [dbo].[ProductDetails](
[Id] [uniqueidentifier] NOT NULL PRIMARY KEY,
[Details] [nvarchar](max) NULL
)

And here is my fluent mapping:

modelBuilder.Entity<Product>()
            .Map(m =>
            {
                m.Properties(t => new { t.Id, t.Name });
                m.ToTable("Product");
            })
            .Map(m =>
            {
                m.Properties(t => new { t.Id, t.Details});
                m.ToTable("ProductDetails");
            });

I want to be able to show a list of products without loading the details field. However, whenever I load a product it always does an INNER JOIN. I want it to only read from Product, but then read from ProductDetails when I read the Details property.

How can this be achieved?

If it is not possible, how else can I implement lazy loading of properties?

Table Splitting is not acceptable as this means the persistence mechanism is dictating the design of the domain.

Edit after CodeCaster's answer:

The domain is fixed - I do not want a solution that introduces a ProductDetails entity. This question is about persisting an existing domain model. Altering the domain does not answer the question.

3

There are 3 answers

7
CodeCaster On BEST ANSWER

How can [lazy-loading scalar properties from split tables] be achieved?

If it is not possible, how else can I implement lazy loading of properties?

You can't, lazy-loading only works for navigation properties.

If you change your model like this:

public class Product
{ 
    public virtual Guid Id {get;set;}
    public virtual string Name {get;set;}

    public virtual ProductDetails Details {get;set;}
}

public class ProductDetails
{ 
    public virtual Guid Product_Id {get;set;}
    public virtual string Details {get;set;}
}

You can utilize lazy loading, where ProductDetails only will be queried when you get the Product.Details property.

[Would] this mean the persistence mechanism is dictating the design of the domain?

Entity models don't have to be domain models.

0
Sam On

You may use the following class I use in my project:

/// <summary>
/// Wrapper class for an unlimited size string property 
/// to allow for lazy loading with Entity Framework.
/// </summary>
public class Text
{
    [MaxLength]
    public string Value { get; set; }

    public static implicit operator string(Text val)
    {
        return val.Value;
    }

    public static implicit operator Text(string val)
    {
        return new Text { Value = val };
    }

    public override string ToString()
    {
        return Value;
    }
}

Since the class overrides the implicit operator, you can treat an object of type Text just as a normal string:

Text myText = "Hello Text";

In your entity class you can then simply create a virtual (Lazy Loading) property:

public virtual Text Comment { get; set; }
0
Dave Cousineau On

You can load just a portion of an entity using an anonymous type, you just can't load the partial entity into the same entity class. (Or, well, you can "manually".)

var products =
   context
   .Products
   .Select(p => new {
      p.ID,
      p.Name
   }).AsEnumerable() // come out of EF
   .Select(anon => new Product { // manually load into product objects
      ID = anon.ID,
      Name = anon.Name
   }).ToList();

Could also just use the anonymous type, or some other type.

You will also have to load the Details property "manually" later, though.