- Home
- LLBLGen Pro
- LLBLGen Pro Runtime Framework
Prefetch LinqMetaData
Joined: 26-Jan-2006
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!
Filename | File size | Added on | Approval |
---|---|---|---|
llblgen-1.png | 74,157 | 21-Feb-2014 19:54.29 | Approved |
Joined: 26-Jan-2006
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.
Joined: 28-Nov-2005
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
Joined: 26-Jan-2006
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!