Prefetch LinqMetaData

Posts   
 
    
Isz
User
Posts: 108
Joined: 26-Jan-2006
# Posted on: 21-Feb-2014 19:54:02   

Hello,

I seem to be stuck on a prefetch that isn't populating a projection graph. The database schema is like this:

SouceAdvisoryProductSiteProductAsset > SouceAdvisoryProductSiteProductAssetTask > SouceAdvisoryProductSiteProductAssetStatus

So an asset can have one or more tasks (see attachment).

My query is on SouceAdvisoryProductSiteProductAssetTask, but I want to navigate up to SouceAdvisoryProductSiteProductAsset and get all of its related SouceAdvisoryProductSiteProductAssetTasks


        partial void OnPartialGetSourceAdvisoryProductSiteProductAssetTasks(ref IQueryable<SourceAdvisoryProductSiteProductAssetTaskMetaData> q)
        {

            q = base.linqMetaData.SourceAdvisoryProductSiteProductAssetTask
                .WithPath(path => path.Prefetch<SourceAdvisoryProductSiteProductAssetEntity>(p => p.SourceAdvisoryProductSiteProductAsset)
                    .SubPath(sub => sub.Prefetch<SourceAdvisoryProductSiteProductAssetTaskEntity>(s => s.SourceAdvisoryProductSiteProductAssetTasks))
                    )
                .Select(c => new SourceAdvisoryProductSiteProductAssetTaskMetaData
                {
...

                    Asset = c.SourceAdvisoryProductSiteProductAsset

...

                }
                )
                ;
        }


Since I am prefetching SourceAdvisoryProductSiteProductAssetEntity, and subpathing back to SourceAdvisoryProductSiteProductAssetTasks, shouldn't I have a collection of tasks on...


  myObject.Asset.SourceAdvisoryProductSiteProductAssetTasks

... but the tasks count is always 0.

I am using LLBLGen 4.1.

Thanks for any assistance!

Attachments
Filename File size Added on Approval
llblgen-1.png 74,157 21-Feb-2014 19:54.29 Approved
Isz
User
Posts: 108
Joined: 26-Jan-2006
# Posted on: 21-Feb-2014 20:38:45   

Furthering my research, there appears to be a difference between just selecting the entity, and assigning the entity to an object, where the latter doesn't wire up the projection.

This works:



        [TestMethod]
        public void TestPrefetch()
        {
            LinqMetaData linqMetaData = new LinqMetaData(DataAccessAdapterFactory.CreateStandardAdapter());

            var tasks = linqMetaData.SourceAdvisoryProductSiteProductAssetTask
                .WithPath(path => path.Prefetch<SourceAdvisoryProductSiteProductAssetEntity>(p => p.SourceAdvisoryProductSiteProductAsset)
                    .SubPath(sub => sub.Prefetch<SourceAdvisoryProductSiteProductAssetTaskEntity>(s => s.SourceAdvisoryProductSiteProductAssetTasks))
                    )
                .Select(c => c )
                .ToList()
                ;

            foreach (var s in tasks)
            {
                Assert.IsTrue(s.SourceAdvisoryProductSiteProductAsset.SourceAdvisoryProductSiteProductAssetTasks.Count > 0);
            }
        }

This does not...




        [TestMethod]
        public void TestPrefetch()
        {
            LinqMetaData linqMetaData = new LinqMetaData(DataAccessAdapterFactory.CreateStandardAdapter());

            var tasks = linqMetaData.SourceAdvisoryProductSiteProductAssetTask
                .WithPath(path => path.Prefetch<SourceAdvisoryProductSiteProductAssetEntity>(p => p.SourceAdvisoryProductSiteProductAsset)
                    .SubPath(sub => sub.Prefetch<SourceAdvisoryProductSiteProductAssetTaskEntity>(s => s.SourceAdvisoryProductSiteProductAssetTasks))
                    )
                .Select(c => new { Asset = c } )
                .ToList()
                ;

            foreach (var s in tasks)
            {
                Assert.IsTrue(s.Asset.SourceAdvisoryProductSiteProductAsset.SourceAdvisoryProductSiteProductAssetTasks.Count > 0);
            }
        }
                    

I'll keep messing with it until I get something that will work out.

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 22-Feb-2014 06:52:41   

The first snippet works because when you use WithPath you should do a query fetch, not an anoymous projection.

About the WithPath, please plase that in the last projection, so, after the .Select(). See examples in the docs.

About your spectation, I think that you are falling into the case of X->Y->X graph. I tried to explain it o this blog post (common mistakes - The X->Y->Z graph: http://www.llblgening.com/archive/2009/10/prefetchpaths-in-depth/#commonmistakes

David Elizondo | LLBLGen Support Team
Isz
User
Posts: 108
Joined: 26-Jan-2006
# Posted on: 22-Feb-2014 21:57:24   

I can definitely see the XYZ problem, and tried several combinations of subpaths to see if I wasn't getting that wrong, but in the end the issue has more to do with the anonymous projection you mention.

I've got a number of custom templates that are built on this projection technique, and they were crafted to provide a DTO-like object to the client (no entities allowed) so I didn't want to change that. After checking out the docs a re-reading a bit more I started exploring the use of nested queries in the projection.


            q = base.linqMetaData.SourceAdvisoryProductSiteProductAssetTask
                .Select(c => new SourceAdvisoryProductSiteProductAssetTaskMetaData
                {
                    ...
                    SiteId = c.SourceAdvisoryProductSiteProductAsset.SiteId,
                    SourceAdvisoryId = c.SourceAdvisoryProductSiteProductAsset.SourceAdvisoryProduct.SourceAdvisoryId,
                    ItDirector = c.SourceAdvisoryProductSiteProductAsset.SiteProductAsset.SiteAsset.ItDirector,
                    WorkflowCompletionDate = c.SourceAdvisoryProductSiteProductAsset.WorkflowCompletionDate,
                    AssessmentStatusName = this.linqMetaData.SourceAdvisoryProductSiteProductAssetTask
                        .WithPath(new PathEdge<SourceAdvisoryProductSiteProductAssetTaskStatusEntity>(SourceAdvisoryProductSiteProductAssetTaskEntity.PrefetchPathSourceAdvisoryProductSiteProductAssetTaskStatu))
                        .Where(s => s.SourceAdvisoryProductSiteProductAssetId == c.SourceAdvisoryProductSiteProductAssetId)
                        .Where(s => s.SourceAdvisoryProductSiteProductAssetTaskTypeId == (int)SourceAdvisoryProductSiteProductAssetTaskType.ASSESSMENT)
                        .OrderByDescending(s => s.SourceAdvisoryProductSiteProductAssetTaskId)
                        .Select(s => s.SourceAdvisoryProductSiteProductAssetTaskStatu.StatusName)
                        .FirstOrDefault(),

                }
                )
                ;

Here I can add my path edge to get the StatusName, but I'm not sure it is required since the squbquery is probably creating the join anyway.

Anyway, I am happy with this.

Thanks daelmo!

smile