Get an entity from EF core without loading all fields

c# entity-framework-core

Question

Let's say I have a model like this:

public class Model {
    [Key]
    public int Id { get; set; }
    public string SmallData { get; set; }
    public byte[] VeryLargeBlob { get; set; }
}

I need to read an entity from the database and use only the field SmallData, and the VeryLargeBlob is not needed. VeryLargeBlob is very large (say, several megabytes) and reading it from database can affect performance.

I understand that I can choose some of the fields in this way:

var data = context.Model.Where(m => m.Id == Id).Select(m => new { Id = m.Id, SmallData = m.SmallData }).FirstOrDefault();

But I need a Model instance and not an anonymous object, so that I can use it for later queries. Even if I hack it and make it return a Model object the instance isn't tracked and won't be compatible with lazy loading.

Is there a way to load only partial data from the model?

1
2
9/19/2018 1:28:14 PM

Popular Answer

Use "Table Splitting" to split a single table among two or more entity classes, allowing you to control if and when you load certain properties. One achieves this by specifying the same table name for multiple entities and using a shared primary key (PK of dependent entities are a FK to the principal entity). Here's an example:

public class PrincipalEntity
{
    [Key]
    public int Id { get; set; }
    public string PrincipalProperty { get; set; }
    public virtual DependentEntity Dependent { get; set; }
}

public class DependentEntity
{
    [Key]
    public int Id { get; set; }
    public string DependentProperty { get; set; }
}

public class PricipalEntityConfiguration : IEntityTypeConfiguration<PrincipalEntity>
{
    public void Configure( EntityTypeBuilder<PrincipalEntity> builder )
    {
        //builder.HasKey( pe => pe.Id );
        builder.HasOne( pe => pe.Dependent )
            .WithOne()
            .HasForeignKey<DependentEntity>( de => de.Id ); // FK is PK
        builder.ToTable( "YourTableName" );
    }
}

public class DependentEntityConfiguration : IEntityTypeConfiguration<DependentEntity>
{
    public void Configure( EntityTypeBuilder<DependentEntity> builder )
    {
        //builder.HasKey( de => de.Id );
        builder.ToTable( "YourTableName" ); // same table name
    }
}

public class TestContext : DbContext
{
    public DbSet<PrincipalEntity> PrincipalEntities { get; set; }
    public DbSet<DependentEntity> DependentEntities { get; set; }

    public TestContext( DbContextOptions options ) : base( options )
    {
    }

    protected override void OnModelCreating( ModelBuilder modelBuilder )
    {
        modelBuilder.ApplyConfiguration( new PricipalEntityConfiguration() );
        modelBuilder.ApplyConfiguration( new DependentEntityConfiguration() );
    }
}

class Program
{
    static void Main( string[] args )
    {
        var options = new DbContextOptionsBuilder<TestContext>()
            .UseSqlServer( "Server=(localdb)\\mssqllocaldb;Database=EFCoreTest;Trusted_Connection=True;" )
            .Options;

        using( var dbContext = new TestContext( options ) )
        {
            var pEntity = new PrincipalEntity()
            {
                PrincipalProperty = "Principal Property Value",
                Dependent = new DependentEntity()
                {
                    DependentProperty = "Dependent Property Value",
                },
            };

            dbContext.PrincipalEntities.Add( pEntity );
            dbContext.SaveChanges();
        }

        using( var dbContext = new TestContext( options ) )
        {
            var pEntity = dbContext.PrincipalEntities
                // eager load dependent
                .Include( pe => pe.Dependent )
                .Single();

            System.Console.WriteLine( "Loaded Principal w/ Dependent Eager-Loaded:" );
            DisplayValues( pEntity );

            dbContext.Entry( pEntity.Dependent ).State = EntityState.Detached;
            dbContext.Entry( pEntity ).State = EntityState.Detached;
            pEntity = dbContext.PrincipalEntities.Single();

            System.Console.WriteLine();
            System.Console.WriteLine( "Load Principal Entity Only:" );
            DisplayValues( pEntity );

            // explicitly load dependent
            dbContext.Entry( pEntity )
                .Reference( pe => pe.Dependent )
                .Load();

            System.Console.WriteLine();
            System.Console.WriteLine( "After Explicitly Loading Dependent:" );
            DisplayValues( pEntity );                
        }
    }

    private static void DisplayValues( PrincipalEntity pe )
    {
        System.Console.WriteLine( $"Principal Entity = {{ Id: {pe.Id}, PrincipalProperty: \"{pe.PrincipalProperty}\" }}" );

        if( null == pe.Dependent )
        {
            System.Console.WriteLine( "Principal Entity's Dependent property is null" );
        }
        else
        {
            System.Console.WriteLine( $"Dependent Entity = {{ Id: {pe.Dependent.Id}, DependentProperty: \"{pe.Dependent.DependentProperty}\" }}" );
        }
    }

Results:

enter image description here

Table in Database:

enter image description here

5
9/19/2018 3:25:34 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow