Select Transformation Example

88 views
Skip to first unread message

Paul Yoder

unread,
Oct 19, 2009, 10:22:35 AM10/19/09
to re-moti...@googlegroups.com
Can someone provide an implementation example of the following code using relinq? Specifically I would like to know how to transform a populated Person object to a Customer object in the example below.
 
var people = new List<Person>();
PopulatePeopleList(people);
var customers = from p in people
                select new Customer
                {
                   Name = p.FirstName + " " + p.LastName,
                   Location = p.City,
                   Notes = p.Memo
                };

Fabian Schmied

unread,
Oct 20, 2009, 4:36:51 AM10/20/09
to re-moti...@googlegroups.com
Hi Paul,

You probably already know this, but just for the sake of completeness:
You can't use re-linq to query from a List<Person> because re-linq is
based on IQueryable<T> and List<T> does not implement IQueryable<T>.
You usually need a class derived from re-linq's QueryableBase<T> as an
entry point for re-linq-based queries.

That aside, to your question. If I understand correctly, you want to
know how to handle the projection when you've already figured out how
to execute the rest of the query (from clauses, where clauses, order
by clauses, etc.) against your query source, right?

The answer is: unless your target query system allows you to specify
such complex projections (and most don't), you'll have to simulate
them in memory. To do so, I'd suggest the following steps:

First, wrap the items coming from your target query system into some
result object; I'll call it ResultItem. ResultItem must provide a
method to access queried objects via the respective IQuerySources the
object originates from:

public class ResultItem
{
private readonly Dictionary<IQuerySource, object>
_resultObjectsBySource = new Dictionary<IQuerySource, object> ();

public void Add (IQuerySource querySource, object resultObject)
{
_resultObjectsBySource.Add (querySource, resultObject);
}

public T GetObject<T> (IQuerySource source)
{
return (T) _resultObjectsBySource[source];
}
}

Then, implement an expression tree visitor that builds an in-memory
projector for the select expression of your QueryModel. An in-memory
projector is a delegate with a signature of "Func<ResultItem, T>"
(where T is the projection's result type) that executes the projection
against a ResultItem. To build it, define a parameter expression for
the ResultItem, then simply replace every
QuerySourceReferenceExpression in the select expression with an
expression that gets the referenced object from that parameter:

protected override Expression VisitQuerySourceReferenceExpression
(QuerySourceReferenceExpression expression)
{
var getObjectGenericMethodDefinition = typeof (ResultItem).GetMethod
("GetObject")
var getObjectMethod =
getObjectGenericMethodDefinition.MakeGenericMethod (expression.Type);
return Expression.Call (_resultItemParameter, getObjectMethod,
Expression.Constant (expression.ReferencedQuerySource));
}

Take the transformed select expression and the ResultItem parameter
and compile them into a delegate; this is your in-memory projector.
You can now apply that projector to the result items stemming from
your query to the target system.

In case that's too abstract, I've put together a sample implementation
(I've wanted to do that for some time anyway) here:
<https://svn.re-motion.org/svn/Remotion-Contrib/Samples/re-linq/ProjectionSupport/>.

Hope this helps,
Fabian

Paul

unread,
Oct 20, 2009, 2:35:04 PM10/20/09
to re-motion Users
Thanks! That's exactly what I was looking for. The sample
implementation helped immensely.
> <https://svn.re-motion.org/svn/Remotion-Contrib/Samples/re-linq/Projec...>.
>
> Hope this helps,
> Fabian

Иван Тихонов

unread,
Nov 8, 2016, 1:49:13 AM11/8/16
to re-motion Users
Please help, a try this example, but always get exception in VisitExpression method. Please explain where the method VisitQuerySourceReferenceExpression is called? i can't understand:(

вторник, 20 октября 2009 г., 11:36:51 UTC+3 пользователь Fabian Schmied написал:

Michael Ketting

unread,
Nov 8, 2016, 11:19:48 AM11/8/16
to re-motion Users
Hello!

VisitQuerySourceReferenceExpression is called when visiting the QuerySourceReferenceExepression type which is introduced by re-linq to represent, well, references to query sources. The details are explained by Fabian in his blog:
https://www.re-motion.org/blogs/mix/2009/09/02/how-to-write-a-linq-provider-the-simple-way-again/
https://www.re-motion.org/blogs/mix/2009/09/22/re-linq-more-than-a-couple-of-visitors/
And the custom projection post:
https://www.re-motion.org/blogs/mix/2009/10/20/re-linq-how-to-perform-a-projection-in-memory/

I have just given the sample a quick spin and did not get exceptions so a bit more context would be needed :)

Note: The sample has been moved some time ago to https://github.com/re-motion/Samples-ReLinq-ProjectionSupport but it's still based on the 2010-version of re-linq.

Best regards, Michael

Иван Тихонов

unread,
Nov 8, 2016, 2:10:27 PM11/8/16
to re-motion Users
Thank you very match it's work, i'am very happy. Excuse me can you give some example how create linq provider with group by? I can't find any example how implement VisitGroupJoinClause. Excuse me if my question stupid:)

вторник, 8 ноября 2016 г., 19:19:48 UTC+3 пользователь Michael Ketting написал:

Michael Ketting

unread,
Nov 10, 2016, 3:14:09 AM11/10/16
to re-motion Users
Glad to hear you got it working!

Group joins: In our SQL backend, we actually don't handle them via VisitGroupJoinClause but rather in https://github.com/re-motion/Relinq-SqlBackend/blob/9f1b4b50d0fb5349604a0fc81764ff0c7178012d/Core/SqlPreparation/SqlPreparationFromExpressionVisitor.cs#L149
There, as you can see, the GroupJoinClause is actually a query source but selecting hierarchical data in a SQL query is always a bit tricky. For instance, we don't support it in the projection since there is no good way to return the data and group joins are mosly used in the context of aggregating subqueries and left outer joins.

So, in short, yes group joins are hard to get right and if your target syntax doesn't have a concept for it, so you might not want to touch this bit of syntax unless you really, really need it. On the other hand, if there is native support available, the translation should be straight forward.

Best regards, Michael

Michael Ketting

unread,
Nov 10, 2016, 3:36:37 AM11/10/16
to re-motion Users
Oh, something was just pointed out to me: In your question, you're referring to "group by" but you're then asking for VisitGroupJoinClause, which represents "join into" in LINQ. Just in case: group by is much easier to do and you just have to handle the GroupByResultOperator.

Best regards, Michael

Иван Тихонов

unread,
Nov 13, 2016, 2:32:28 PM11/13/16
to re-motion Users
Thank you very match.It's very help me. And I reale confused with VisitGroupJoinClause:)) 

четверг, 10 ноября 2016 г., 11:36:37 UTC+3 пользователь Michael Ketting написал:

Michael Ketting

unread,
Nov 14, 2016, 2:52:22 AM11/14/16
to re-motion Users
Thanks for the update! Glad I could help :)
Reply all
Reply to author
Forward
0 new messages