score:1
you are very close with your 2nd approach!
let's say you define the projection of the product entity to the dto (the mapper as you call it) like you did:
expression<func<product, productdto>> productprojection = prod => new productdto
{
id = prod.id,
dateoftransaction = prod.date
// ...
};
and the projection of the client entity to it's dto like this (slightly simpler, but logically equivalent to what you did):
expression<func<client, clientdto>> clientprojection = client => new clientdto
{
id = client.clientid,
firstname = client.firstname,
// ...
products = client.products.select(productprojection.compile()).tolist(),
// ...
};
the compiler let's you do so, but the queryable will not understand that. however what you have achieved is that the productprojection
is somehow contained in the expression tree. all you have to do is some expression manipulation.
if you look at the subtree the compiler builds for the argument to .select
you'll find a methodcallexpression
- the call to .compile()
. it's .object
expression - the thing that is to be compiled - is a memberexpression
accessing a field named productprojection
(!) on an constantexpression
containing an instance of an oddly named compiler generated closure class.
so: find .compile()
calls and replace them with what would be compiled, ending up with the very expression tree you had in your original version.
i'm maintaining a helper class for expression stuff called express
. (see another answer that deals with .compile().invoke(...)
for a similar situation).
clientprojection = express.uncompile(clientprojection);
var clientlist = dbclients.select(clientprojection).tolist();
here's the relevant snipped of the express
class.
public static class express
{
/// <summary>
/// replace .compile() calls to lambdas with the lambdas themselves.
/// </summary>
public static expression<tdelegate> uncompile<tdelegate>(expression<tdelegate> lambda)
=> (expression<tdelegate>)uncompilevisitor.singleton.visit(lambda);
/// <summary>
/// evaluate an expression to a value.
/// </summary>
private static object getvalue(expression x)
{
switch (x.nodetype)
{
case expressiontype.constant:
return ((constantexpression)x).value;
case expressiontype.memberaccess:
var xmember = (memberexpression)x;
var instance = xmember.expression == null ? null : getvalue(xmember.expression);
switch (xmember.member.membertype)
{
case membertypes.field:
return ((fieldinfo)xmember.member).getvalue(instance);
case membertypes.property:
return ((propertyinfo)xmember.member).getvalue(instance);
default:
throw new exception(xmember.member.membertype + "???");
}
default:
// note: it would be easy to compile and invoke the expression, but it's intentionally not done. callers can always pre-evaluate and pass a member of a closure.
throw new notsupportedexception("only constant, field or property supported.");
}
}
private sealed class uncompilevisitor : expressionvisitor
{
public static uncompilevisitor singleton { get; } = new uncompilevisitor();
private uncompilevisitor() { }
protected override expression visitmethodcall(methodcallexpression node)
{
if (node.method.name != "compile" || node.arguments.count != 0 || node.object == null || !typeof(lambdaexpression).isassignablefrom(node.object.type))
return base.visitmethodcall(node);
var lambda = (lambdaexpression)getvalue(node.object);
return lambda;
// alternatively recurse on the lambda if it possibly could contain .compile()s
// return visit(lambda); // recurse on the lambda
}
}
}
score:1
use linqkit to expand user-defined lambda functions into the lambdas needed in the query:
Source: stackoverflow.com
Related Query
- Query and map complex objects
- Performing part of a IQueryable query and deferring the rest to Linq for Objects
- Can you map the results of a manual SQL query to objects in Entity Framework?
- Avoid extra loop and could not find implementation of query pattern for source type int Select not found
- Wrapping a complex linq query with a Try-Catch block and catching the correct Exceptions
- Flatten and group complex objects in Linq and preserve null children
- Code Example for Add DateTime and TimeSpan in EF query
- Linq query to find duplicate objects based on multiple fields AND property is null
- query and create objects with a one to many relationship using LINQ
- linq query to find the objects that are the maximum and the minimum
- How to break complex query into different methods to achieve less code complexity
- Complex LINQ query to build two lists, cast each value in each list, and combine lists?
- How to properly (deep) map complex objects with C# LINQ?
- Linq to entities query that returns a count and a list of objects
- How to query a complex result set from EntityFramework and display the result set in MVC.
- How can I check the number of calls to the database in LINQ query when using .NET Core and Code First?
- Is better Linq or SQL query for complex calculations and aggregations?
- MongoDb c# Linq query and return a collection's child objects
- What design pattern should I use to create an easy binding map between a query and textboxes for Linq search screens?
- Linq query to join two objects and calculate sum
- Entity Framework - complex query - and CSV export
- How to Query and Enumerate complex JSON object using JSON.Net in C#
- How to run a LINQ query on a collection of objects and a collection inside of each object
- How to query the average from a certain property in an Entity and return it in a List of List of objects in LINQ?
- Multiple Grouping with IQueryable and returning a list of objects in C# linq query
- How to bind and save an object containing a list of objects to database context in ASP.NET MVC with EF code first?
- Map SQL with JOIN, GROUP BY, and SUM to Entity Framework query
- How do I use the having clause on an aggregate in a complex group by and join query in LINQ
- A LINQ question: map query expression to c# code
- Linq query referencing objects and a string array
More Query from same tag
- select distinct out of three column connectiontable
- Nested group by based on flatten record set
- How to OR a foreach looped linq lambda expression
- Inline method that support translation to sql
- Linq-to-Sql: Use LinqDataSource to programmatically retrieve data
- NHibernate 3.1 migration problem with Linq
- Including a percent calculation in LINQ query
- Add a parent tag using XML linq
- IEnumerable takes too long to process when filtering on it
- LINQ: Select all from each group except the first item
- How to select objects based on values in sub collection?
- Limiting a query to the rows created today (Linq-to-Entities, Datetime)
- Linq to Sql - Incorrect syntax by keyword 'IS'
- How to sum Time from a DataGridView Columns
- C# Define local variable with an linq enumeration
- Write a translatable method for LINQ TO Entities
- Read CSV data in batches and Process it
- How can i look at query LINQ
- Cannot implicitly convert type 'System.Collections.Generic.List in asp.net MVC
- How to check if all elements of a list are different
- split a List<Product> into SubLists<Product>
- Order by splitted string C# and LINQ
- Tracking external changes to a database with LINQ-to-SQL
- How to create a dictionary from a list with an object as key
- Grouping rows in a DataTable by column, then summing the contents of other columns in that group
- Perform Calculations Within List Using Linq and Lambda Expressions
- Transforming two queries into one query in LINQ
- How to Convert Method Based query to Query Expression in Linq
- How to count below extensions? by using c#
- Find duplicate xelements