Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding Orchard Joins and Data Relations

In Orchard, how is a module developer able to learn how "joins" work, particularly when joining to core parts and records? One of the better helps I've seen was in Orchard documentation, but none of those examples show how to form relations with existing or core parts. As an example of something I'm looking for, here is a snippet of module service code taken from a working example:

_contentManager
    .Query<TaxonomyPart>()
    .Join<RoutePartRecord>()
    .Where(r => r.Title == name)
    .List()

In this case, a custom TaxonomyPart is joining with a core RoutePartRecord. I've investigated the code, and I can't see how that a TaxononmyPart is "joinable" to a RoutePartRecord. Likewise, from working code, here is another snippet driver code which relates a custom TagsPart with a core CommonPartRecord:

List<string> tags = new List<string> { "hello", "there" };
IContentQuery<TagsPart, TagsPartRecord> query = _cms.Query<TagsPart, TagsPartRecord>();
query.Where(tpr => tpr.Tags.Any(t => tags.Contains(t.TagRecord.TagName)));
IEnumerable<TagsPart> parts =
    query.Join<CommonPartRecord>()
    .Where(cpr => cpr.Id != currentItemId)
    .OrderByDescending(cpr => cpr.PublishedUtc)
    .Slice(part.MaxItems);

I thought I could learn from either of the prior examples of how to form my own query. I did this:

List<string> tags = new List<string> { "hello", "there" };
IContentQuery<TagsPart, TagsPartRecord> query = _cms.Query<TagsPart, TagsPartRecord>();
query.Where(tpr => tpr.Tags.Any(t => tags.Contains(t.TagRecord.TagName)));
var stuff =
    query.Join<ContainerPartRecord>()
    .Where(ctrPartRecord => ctrPartRecord.ContentItemRecord.ContentType.Name == "Primary")
    .List();

The intent of my code is to limit the content items found to only those of a particular container (or blog). When the code ran, it threw an exception on my join query saying {"could not resolve property: ContentType of: Orchard.Core.Containers.Models.ContainerPartRecord"}. This leads to a variety of questions:

  1. Why in the driver's Display() method of the second example is the CommonPartRecord populated, but not the ContainerPartRecord? In general how would I know what part records are populated, and when?
  2. In the working code snippets, how exactly is the join working since no join key/condition is specified (and no implicit join keys are apparent)? For example, I checked the data migration file and models classes, and found no inherent relation between a TagsPart and a CommonPartRecord. Thus, besides looking at that sample code, how would anyone have known in the first place that such a join was legal or possible?
  3. Is the join I tried with TagsPart and ContainerPartRecord legal in any context? Which?
  4. Is the query syntax of these examples primarily a reflection of Orchard, of NHibernate, or LINQ to NHibernate? If it is primarily a reflection of NHibernate, then which NHibernate book or article is recommended reading so that I can dig deeper into Orchard?

It seems there is a hole in the documentation regarding these kinds of thoughts and questions, which makes it hard to write a module. Whatever answers can be found for this topic, I'd be glad to compile into an article or community Orchard documentation.

like image 554
Brent Arias Avatar asked Jan 02 '12 20:01

Brent Arias


1 Answers

  1. The join is only there to enable the where that follows it. It doesn't mean that the part being joined will be actually brought down from the DB. That will happen no matter what with the latest 1.x source, and will happen lazily with 1.3.
  2. You don't need a condition as you can only join parts this way. The join condition is implicit: parts are joined by the item id.
  3. Yes. What is not legal is that the condition in the where is using data that is not available from the joined part records.
  4. Those examples are all Orchard Content Manager queries, so they are fairly constrained, but also fairly easy to build as long as you don't step outside of their boundaries because so much can be assumed and will happen implicitly. If you need more control, you could use the new HQL capabilities that were added in the latest 1.x drops.

As for holes in the documentation, well, but of course. The documentation that we have today is only covering a very small part of the platform. Your best reference today is the source code. Any contribution you could make to this is highly appreciated by us and by the rest of the community. Let me know if you need help with this.

like image 141
Bertrand Le Roy Avatar answered Oct 18 '22 19:10

Bertrand Le Roy