Expression must be a MemberExpression System.Exception

Posts   
 
    
tomahawk
User
Posts: 169
Joined: 02-Mar-2005
# Posted on: 24-Sep-2010 04:26:05   

"Expression must be a MemberExpression" System.Exception thrown when the following query is hit at runtime.

Any clues as to what this means? I did a search on the forums and came up blank.

The following is the query:


            var q = (from t in Context.BankTransaction select t)
                .WithPath(transPath => transPath
                    .Prefetch<ActivityEntity>(a => a.Activities.Where(a2 => a2.ActivityId == activityID)));

Please let me know where to begin looking.

Using SD.LLBLGen.Pro.LinqSupportClasses.NET35 version 2.6.10.0517

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 24-Sep-2010 07:05:18   

What is Context.BankTransaction? Please post the full relevant code.

Also pleaso post the exception stack trace. Thanks.

David Elizondo | LLBLGen Support Team
tomahawk
User
Posts: 169
Joined: 02-Mar-2005
# Posted on: 27-Sep-2010 22:42:54   

Context is an instance of the generated LinqMetaData object. So the addition to the code above would be:

Context = new LinqMetaData();

StackTrace:

   at SD.LLBLGen.Pro.LinqSupportClasses.PrefetchPathAPI.PathEdgeRootParser`1.ParseComplexPathSpecification[TDestination](MemberExpression expression)
   at SD.LLBLGen.Pro.LinqSupportClasses.PrefetchPathAPI.PathEdgeRootParser`1.Prefetch[TDestination](Expression`1 expression)
   at CL.Service.CLDataService.<>c__DisplayClass9.<GetActivityWithTransaction>b__1(IPathEdgeRootParser`1 transPath) in C:\Users\Josh\Documents\Visual Studio 2008\Projects\CL.Service\CLDataService.cs:line 125
   at SD.LLBLGen.Pro.LinqSupportClasses.QueryableExtensionMethods.WithPath[TSource](IQueryable`1 source, Func`2 edgeSpecifierFunc)
   at CL.Service.CLDataService.GetActivityWithTransaction(Int32 activityID) in C:\Users\Josh\Documents\Visual Studio 2008\Projects\CL.Service\CLDataService.cs:line 124
   at Activity.ViewModels.BankTransactionEditVM.LoadEntity(Int32 primaryKey) in C:\Users\Josh\Documents\Visual Studio 2008\Projects\Activity\ViewModels\BankTransactionEditVM.cs:line 104
   at CL.Infrastructure.EntityListModel`1.Edit(Int32 pKey) in C:\Users\Josh\Documents\Visual Studio 2008\Projects\CL.Infrastructure\DocumentModel\EntityListModel.cs:line 69
   at lambda_method(Closure , Object , Object[] )
   at Caliburn.Core.Invocation.MethodFactory.Procedure.SafeInvoke(Object instance, Object[] parameters) in c:\Projects\BlueSpire\Caliburn\branches\v1.1\src\Caliburn.Core\Invocation\MethodFactory.cs:line 146
Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 28-Sep-2010 09:05:52   

Is there any Polymorphism (Inheritance) in the fetched Graph? Have you tried using PathEdges?

tomahawk
User
Posts: 169
Joined: 02-Mar-2005
# Posted on: 28-Sep-2010 09:58:20   

Activity is a supertype, but none of the subtypes are being queried for. BankTransaction stands alone.

I can try PathEdge objects tomorrow. Are there cases where they are the only option?

Another note is I am compiling against .NET 4.0

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 28-Sep-2010 10:29:19   

As I can't see your entity structure, I'm not 100% sure, but it sounds similar to an issue posted before in a HelpDesk thread (which you can't access).

But maybe reading the following reply will give you a hint about the issue:

Otis wrote:

It's indeed a problem with the Lambda expression approach. The example is the following: Employee <- Manager <- Boardmember BoardMember has a m:1 relation with company car.

So if I want to fetch all employees and for boardmembers also the companycars, I've to do this:

LinqMetaData metaData = new LinqMetaData(adapter); var q = (from e in metaData.Employee select e).WithPath(new PathEdge<CompanyCarEntity>(BoardMemberEntity.PrefetchPathCompanyCar));

which uses the pathedge approach. If I wanted to use the lambda expression approach, I would have to do: LinqMetaData metaData = new LinqMetaData(adapter); var q = (from e in metaData.Employee select e).WithPath(p=>p.Prefetch<CompanyCarEntity>(emp=>emp.CompanyCar));

but this doesn't compile as emp is of type 'Employee'. Would I use: .WithPath<BoardMemberEntity>(p=>p.Prefetch<CompanyCarEntity>(emp=>emp.CompanyCar));

instead, it's also a problem because the queryable<BoardMemberEntity> can't be cast to queryable<EmployeeEntity> which is the same as List<String> can't be cast to List<object>

i.o.w.: for the first node, you've to use a pathedge if you want to specify polymorphic fetches, to make it work properly. This can't be changed really, because of the generics which have to be specified at some point, and the source type, which should be overriden with the subtype, here BoardMemberEntity, is already set to the type of the resultset, employee.

tomahawk
User
Posts: 169
Joined: 02-Mar-2005
# Posted on: 01-Oct-2010 00:13:34   

Using the PathEdge works...but it didn't yield the results I need. It turns out I had the where clause in the wrong place. The following solved it.

var q = (from t in Context.BankTransaction where t.Activities.Contains(new ActivityEntity(activityID)) select t)
                .WithPath(transPath => transPath
                    .Prefetch<ActivityEntity>(a => a.Activities)));

I should let you know of a bug I found, though.

I have the following entities:

BankTransaction Activity Contact

BankTransaction has many Activities BankTransaction has a Contact Activity has a Contact

Contact is a supertype (subtype Individual, Business). Activity is a supertype.

When I use the following query:

var q = (from trans in Context.BankTransaction
                     where trans.Activities.Contains(new ActivityEntity(activityID))
                     select trans)
                .WithPath(transPath => transPath
                    .Prefetch<ActivityEntity>(a => a.Activities)
                    .SubPath(activityPath => activityPath
                        .Prefetch(c => c.Contact)))
                 .Prefetch(tc => tc.Contact)
                 .Prefetch(tb => tb.TransactionStatus));

The retrieved BankTransaction's Contact is accurate, and the Activities collection properly contains 1 ActivityEntity instance. However, the ActivityEntity's Contact is, incorrectly, that of the BankTransaction. In the database the Activity is linked to a different contact, and the traced SQL query shows it returning the correct query...but when the ORM returns the objects, it is the wrong Contact.

Now, if I use the same query, (resulting in the same SQL) but change the order of the BankTransaction Contact path, to be like so:

            var q = (from trans in Context.BankTransaction
                     where trans.Activities.Contains(new ActivityEntity(activityID))
                     select trans)
                .WithPath(transPath => transPath
                    .Prefetch(tc => tc.Contact)
                    .Prefetch<ActivityEntity>(a => a.Activities)
                    .SubPath(activityPath => activityPath
                        .Prefetch(c => c.Contact)))
                    .Prefetch(ts=>ts.TransactionStatus));

then the proper Contact for Activity is populated.

I've also confirmed this problem when using just standard, non-linq API objects, like PrefetchPathElement2.

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 01-Oct-2010 08:34:52   

I've also confirmed this problem when using just standard, non-linq API objects, like PrefetchPathElement2.

Could you please post that (repro) code too.

Thanks.

tomahawk
User
Posts: 169
Joined: 02-Mar-2005
# Posted on: 05-Oct-2010 02:25:52   

This code below also demonstrates the issue with the same entities.


            ActivityEntity activity = new ActivityEntity(activityID);
            using (DataAccessAdapter adapter = proxy.Adapter)
            {
                PrefetchPath2 activityPath = new PrefetchPath2(CL.DAL.EntityType.ActivityEntity);
                activityPath.Add(ActivityEntity.PrefetchPathContact);

                IPrefetchPathElement2 transactionPath = activityPath.Add(ActivityEntity.PrefetchPathBankTransaction);
                transactionPath.SubPath.Add(BankTransactionEntity.PrefetchPathContact);
                transactionPath.SubPath.Add(BankTransactionEntity.PrefetchPathTransactionStatus);

                adapter.FetchEntity(activity, activityPath);
            }
Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 05-Oct-2010 09:58:16   

I can't reproduce it with the following code:

            var activity = new ActivityEntity(1);
            using (var adapter = new DataAccessAdapter())
            {
                var activityPath = new PrefetchPath2(EntityType.ActivityEntity);

                activityPath.Add(ActivityEntity.PrefetchPathContact);

                var transactionPath = activityPath.Add(Activity2Entity.PrefetchPathBankTrans);
                transactionPath.SubPath.Add(BankTransEntity.PrefetchPathContact);

                adapter.FetchEntity(activity, activityPath);

                MessageBox.Show(activity.Contact.Name);
                MessageBox.Show(activity.BankTrans.Contact.Name);
            }

I've created a test database with only these 3 tables, filled it with some test data.

Could you try to reproduce it using another small repro database as I did. (no inheritance or other irrelevant tables).

If you can't reproduce it, then we will need your database.