When using LINQ to Entities, is there a way to reuse a block of a select statment in other select stements?
For example, in the below code, I'm using LINQ to select a customer device object from my database. I also select a related Model object from a table that is joined to the customer devices table.
list = context.PTT_CUSTOMER_DEVICES
.Include(...)
.Select(d => new CustomerDevice
{
customerAssetTag = d.CustomerAssetTag,
customerDeviceID = d.CustomerDeviceID,
//This section is used in several LINQ statements throughout the application.
Model = new Model()
{
ModelID = d.PTS_MODELS.ModelID,
Name = d.PTS_MODELS.Name,
Make = new Make()
{
MakeID = d.PTS_MODELS.PTS_MAKES.MakeID,
Name = d.PTS_MODELS.PTS_MAKES.Name
}
}
})...
There are, however, other objects in the database that also reference the Model table. In my select statements for those other tables, I basically copied the same Model = new Model() code to a select statement for those different tables.
What I'm wondering is, is it possible to store and reuse that block of code in multiple selects? Possibly using an extension method?
As an alternative to Func<>
s, you can also make use of extension methods to reuse the conversions between your entity types to and other POCOs.
public static IQueryable<CustomerDevice> ToCustomerDevice(this IQueryable<PTT_CUSTOMER_DEVICES> devices)
{
return devices.Select(d => new CustomerDevice
{
customerAssetTag = d.CustomerAssetTag,
customerDeviceID = d.CustomerDeviceID
}
}
However, EF will not allow you to nest these, and will complain that it cannot convert the nested extension method to SQL.
A work around for this can be to perform the transform in memory, rather than in SQL:
public static Model ToModel(this PTS_MODELS model)
{
return new Model()
{
ModelID = model.ModelID,
Name = model.Name,
Make = new Make()
{
MakeID = model.PTS_MAKES.MakeID,
Name = model.PTS_MAKES.Name
}
};
}
public static IEnumerable<CustomerDevice> ToCustomerDevice(this IQueryable<PTT_CUSTOMER_DEVICES> devices)
{
return devices
.Include(d => d.PTS_MODELS.PTS_MAKES)
.AsEnumerable() // Evaulate everything that follows in memory
.Select(d => new CustomerDevice
{
customerAssetTag = d.CustomerAssetTag,
customerDeviceID = d.CustomerDeviceID,
Model = d.PTS_MODELS.ToModel()
});
}
Since you are now returning an IEnumerable<>
any further Where()
conditions will be evaluated in memory, rather than in SQL, so its important that ToCustomerDevice()
is your last call.