I have the following CompilerContainer:

/// <summary>LINQ implementation for <see cref="QualificationAssignment.Current"/> property.</summary>
        [Compiler(typeof (QualificationAssignment), "Current", TargetKind.PropertyGet)]
        public static Expression Current(Expression assignmentExpression)
        {
            // Create the expression
            Expression<Func<QualificationAssignment, bool>> expression =
                assignment =>
                assignment.Active && assignment.Start <= DateTime.Now &&
                (!assignment.End.HasValue || assignment.End.Value >= DateTime.Now);

            // Bind parameters to expression
            return expression.BindParameters(assignmentExpression);
        }

As you can see, the QualificaitonAssignment.Current property is not-persistent, and its implementation depends on the persistent fields Active, Start, and End.

Making a CompilerContainer for the QualificaitonAssignment.Current property allows me to use the property in LINQ... but I should also be able to use it in Prefetch too! Is this possible?


Updated at 19.02.2010 12:27:00

Sorry, the object model in my original post does not describe the scenario well.

Consider the following model:

class Customer

--------------
[Field] string Name { get; set; }
EntitySet<Order> Orders { get; private set; } <-- paired to Order.Customer property
[NotPersistent] int NumOrders { get { return Orders.Count; }}

class Order

-------------
[Field] Customer Customer { get; set; }
... other properties ...

A developer wants to fetch all Customer entities and display their Name and NumOrders property values.

var result = Query.All<Customer>();

foreach (var c in result)
  Print(c.Name+ " " + c.NumOrders);

On each enumeration, DO will query for the NumOrders value. I want to avoid this. I want all the data to be loaded in one query.

Therefore, the ideal code is the following:

var result = Query.All<Customer>().Prefetch(c=> c.Name).Prefetch(c => c.NumOrders);

But this is not possible, because Customer.NumOrders is not persistent.

Rather, the developer must know about the implementation of Customer.NumOrders and prefetch the properties used in its implementation:

var result = Query.All<Customer>().Prefetch(c=> c.Name).Prefetch(c => c.Orders);

A developer should not need to know the implementation of Customer.NumOrders in order to have its value prefetched.

Since CompilerContainer is used to generate the SQL when a non-persistent property/method is used, can it also be used to generate the prefetch commands when a non-persistent property/method is used within a prefetch statement?

If not, can their be another solution?

This thread was imported from our support forum. The original discussion may contain more detailed answer.

asked Feb 19 '10 at 00:28

ara's gravatar image

ara
395868791


One Answer:

Err... What exactly is necessary?

Our prefetch API is based on sequences, not on queries - i.e. we do nearly the following:

  • Split the sequence into bulks

  • Decide what must be prefetched for each bulk (particular objects, additional properties, EntitySets)

  • Group planned prefetch requests to make the queries more efficient (i.e. use IN (...), etc.)

  • Execute them as future queries (i.e. they're sent in batches by ~ 25 items at once).

Result: prefetch goes noticeably slower than regular materialization (~ 4...5 times) - mainly, because we must check & plan everything. But this is anyway faster then regular materialization in e.g. NHibernate. It might be faster in future - we didn't seriously optimize anything there for now. In exchange, you get very flexible mechanism for this, that won't query the server at all if everything is available (will be attractive when there are caches).

Another way fo prefetching the information is adding it to final .Select (there will be joins and future queries for subqueries).

Any of these ways does not imply you should anything special to affect on prefetch. If the query returns right objects, further prefetch-related parts will be executed properly.


In short, this isn't easy: prefetch API works on IEnumerable<t> level, so we can't pass such "full" queries to query transformation pipeline (i.e. LINQ rewriters).

The only quick solution I see so far is to use your own version of Prefetch that is able to successfully handle such cases.

More complex solution can be e.g. an API (similar to LINQ compilers\rewriters) allowing you to handle prefetches for "unknown" properties, if they're passes to prefetch API.

answered Feb 19 '10 at 07:22

Alex%20Yakunin's gravatar image

Alex Yakunin
29714412

Clear. Let me think about this a bit today, I'll provide a reply a bit later (must finish few things, + the case really seems not so simple).

(Feb 19 '10 at 07:22) Alex Yakunin Alex%20Yakunin's gravatar image
Your answer
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!
toggle preview

Subscription:

Once you sign in you will be able to subscribe for any updates here

Tags:

×574

Asked: Feb 19 '10 at 00:28

Seen: 2,536 times

Last updated: Feb 19 '10 at 00:28

powered by OSQA