Joshua Frank
Joshua Frank

Reputation: 13848

How can I create a reusable Entity Framework projection expression?

In my database, there are tables with dozens of columns:

Table MyEntity: int Id string Name string Email ...dozens of other columns I never use in this project

The class generated by EF has properties for those extra columns, and a simple query gets all those extra columns, wastefully.

Instead, I want to have a thin class, like so:

class MyEntity { public int Id; public string Name; public string Email; }

When I query, I want to create instances of my thin object, and obviously, I can do this:

from x in MyEntity
select new MyEntity {Id = x.Id, Name = x.Name, Email = x.Email };

But I do this a lot, and typing out the properties every time gets very tedious (and error prone, because I could forget one).

So I'm trying to do something like this instead:

from x in MyEntity
select x.ToLiteEntity();

But I'm not sure how to write ToLiteEntity so that it creates an expression that gets added to the query, so that it knows to select only the needed columns from the database. How can I do this?

Upvotes: 4

Views: 1983

Answers (2)

DrewJordan
DrewJordan

Reputation: 5314

You can abstract this to a layer above the database. When you want to retrieve your 'lite' objects, call a separate method:

public IQueryable<MyEntity> GetLiteMyEntities(DbContext c, string Name) // your implementation of DbContext, not actually DbContext
{
    return from me in c.MyEntity 
        select new MyEntity {Id = x.Id, Name = x.Name, Email = x.Email };
}

EDIT: If you need to filter on other fields that you don't want to return, you can compose your filter query first, and then use a method that takes an IQueryable:

public IQueryable<MyEntity> GetLiteMyEntities(IQueryable<MyEntity> query)
{
    return from me in query 
        select new MyEntity {Id = x.Id, Name = x.Name, Email = x.Email };
}

// build your filter first
from x in MyEntity 
where x.someSpecialID == 42
select x;

// then pass it to get your lite object
var lite = GetLiteMyEntities(x);

Even better, make it an extension method:

public IQueryable<MyEntity> GetLiteMyEntities(this IQueryable<MyEntity> query)
{
    return from me in query 
        select new MyEntity {Id = x.Id, Name = x.Name, Email = x.Email };
}

var lite = (from x in MyEntity 
where x.someSpecialID == 42
select x).GetLiteMyEntities();

Upvotes: 2

jbl
jbl

Reputation: 15413

You may use Queryable Extensions from AutoMapper

The .ProjectTo() will tell AutoMapper's mapping engine to emit a select clause to the IQueryable that will inform entity framework that it only needs to query the Name column of the Item table, same as if you manually projected your IQueryable to an OrderLineDTO with a Select clause.

Upvotes: 1

Related Questions