How to filter related Content Parts within a Orchard CMS Query

感情迁移 提交于 2020-01-15 12:33:17

问题


Goal:

I have a widget that attempts to return blog posts that have matching tags to the current item.

Problem:

So I have acquired the current ContentItem in my widget and I have returned the TagsPart of that ContentItem:

var itemTagsPart = _contentManager.Get<TagsPart>(currentContentItem.Id);

And I am now trying to create a query to return blog posts that have a tag record with a matching TagName.

var blogs = _contentManager.Query(VersionOptions.Published, "BlogPost")
                .Join<TagsPartRecord>().Where(tpr => tpr.Tags.Any(tag => itemTagsPart.CurrentTags.Any(t => t.TagName == tag.TagRecord.TagName)))
                .Slice(part.MaxPosts);

Unfortunately, on the predicate for filtering the returned TagsPartRecord records, I get a null reference exceptions. I haven't been able to reduce exactly which field would cause this, but I have added null checks in my predicate (above code has them all removed to keep it clean for here). Example

var blogs = _contentManager.Query(VersionOptions.Published, "BlogPost")
                .Join<TagsPartRecord>().Where(tpr => tpr.Tags != null && tpr.Tags.Any(tag => tag != null && itemTagsPart.CurrentTags.Any(t => t.TagName != null &&  t.TagName == tag.TagRecord.TagName)))
                .Slice(part.MaxPosts);

I have even tried exacting out the itemTagsPart.CurrentTags.ToList().

Below is the error I am getting. However, I read on this posted Question that you can't do this type of filter, at least not the way I am going about it. How can I filter the returned blog posts based on matching tagsParts?

Version: 1.7

The error:

Orchard.ContentManagement.Drivers.Coordinators.ContentPartDriverCoordinator - NullReferenceException thrown from IContentPartDriver by TrueFit.RelatedBlogPosts.Drivers.RelatedBlogPostsWidgetDriver
System.NullReferenceException: Object reference not set to an instance of an object.
at NHibernate.Linq.Visitors.WhereArgumentsVisitor.GetExistsCriteria(MethodCallExpression expr)
at NHibernate.Linq.Visitors.WhereArgumentsVisitor.VisitMethodCall(MethodCallExpression expr)
at NHibernate.Linq.Visitors.ExpressionVisitor.Visit(Expression exp)
at NHibernate.Linq.Visitors.WhereArgumentsVisitor.GetExistsCriteria(MethodCallExpression expr)
at NHibernate.Linq.Visitors.WhereArgumentsVisitor.VisitMethodCall(MethodCallExpression expr)
at NHibernate.Linq.Visitors.ExpressionVisitor.Visit(Expression exp)
at NHibernate.Linq.Visitors.ExpressionVisitor.VisitLambda(LambdaExpression lambda)
at NHibernate.Linq.Visitors.ExpressionVisitor.Visit(Expression exp)
at NHibernate.Linq.Visitors.WhereArgumentsVisitor.VisitUnary(UnaryExpression expr)
at NHibernate.Linq.Visitors.ExpressionVisitor.Visit(Expression exp)
at NHibernate.Linq.Visitors.RootVisitor.HandleWhereCall(MethodCallExpression call)
at NHibernate.Linq.Visitors.RootVisitor.VisitMethodCall(MethodCallExpression expr)
at NHibernate.Linq.Visitors.ExpressionVisitor.Visit(Expression exp)
at NHibernate.Linq.Visitors.NHibernateQueryTranslator.Translate(Expression expression, QueryOptions queryOptions)
at Orchard.ContentManagement.DefaultContentQuery.Where[TRecord](Expression`1 predicate) in c:\inetpub\Orchard\src\Orchard\ContentManagement\DefaultContentQuery.cs:line 89
 at Orchard.ContentManagement.DefaultContentQuery.ContentQuery`2.Orchard.ContentManagement.IContentQuery<T,TR>.Where(Expression`1 predicate) in c:\inetpub\Orchard\src\Orchard\ContentManagement\DefaultContentQuery.cs:line 237
 at TrueFit.RelatedBlogPosts.Drivers.RelatedBlogPostsWidgetDriver.Display(RelatedBlogPostsWidgetPart part, String displayType, Object shapeHelper)
at System.Dynamic.UpdateDelegates.UpdateAndExecute4[T0,T1,T2,T3,TRet](CallSite site, T0 arg0, T1 arg1, T2 arg2, T3 arg3)
at Orchard.ContentManagement.Drivers.ContentPartDriver`1.Orchard.ContentManagement.Drivers.IContentPartDriver.BuildDisplay(BuildDisplayContext context) in c:\inetpub\Orchard\src\Orchard\ContentManagement\Drivers\ContentPartDriver.cs:line 27
at Orchard.ContentManagement.Drivers.Coordinators.ContentPartDriverCoordinator.<>c__DisplayClassa.<BuildDisplay>b__9(IContentPartDriver driver) in c:\inetpub\Orchard\src\Orchard\ContentManagement\Drivers\Coordinators\ContentPartDriverCoordinator.cs:line 47
at Orchard.InvokeExtensions.Invoke[TEvents](IEnumerable`1 events, Action`1 dispatch, ILogger logger) in c:\inetpub\Orchard\src\Orchard\InvokeExtensions.cs:line 17

回答1:


I'm working on a site where we filter blog posts based on a single tag name like this:

// Get the blog that contains the posts you want to filter
BlogPart blog = _contentManager.Query<BlogPart, BlogPartRecord>(VersionOptions.Published)
                                                      .Join<TitlePartRecord>()
                                                      .Where(t => t.Title == "your-blog-name")
                                                      .Slice(0, 1).FirstOrDefault();

// Query for blog posts that contain a tag called "my-tag"
IEnumerable<BlogPostPart> posts = _contentManager.Query(VersionOptions.Published, "BlogPost")
                                               .Join<CommonPartRecord>()
                                               .Where(cr => cr.Container == blog.Record.ContentItemRecord)
                                               .Join<TagsPartRecord>()
                                               .Where(tpr => tpr.Tags.Any(t => t.TagRecord.TagName == "my-tag"))
                                               .WithQueryHints(new QueryHints().ExpandRecords<TagsPartRecord>().ExpandParts<TagsPart>())
                                               .Slice(maxPosts)
                                               .Select(ci => ci.As<BlogPostPart>());

Based on this, I would guess (though I haven't tested) that with a string collection of tag names, you can change this line:

.Where(tpr => tpr.Tags.Any(t => t.TagRecord.TagName == "my-tag"))

to this line (where your tag name collection is myTags):

.Where(tpr => tpr.Tags.Any(t => myTags.Contains(t.TagRecord.TagName)))

If that doesn't work, you can create a list of blog post parts, loop through your collection of tag names, and use the original query to get the blog posts for each tag name:

// Get the blog that contains the posts you want to filter
BlogPart blog = _contentManager.Query<BlogPart, BlogPartRecord>(VersionOptions.Published)
                                                          .Join<TitlePartRecord>()
                                                          .Where(t => t.Title == "your-blog-name")
                                                          .Slice(0, 1).FirstOrDefault();
List<BlogPostPart> blogPosts = new List<BlogPostPart>();
foreach (string tag in myTags){
    // Query for blog posts that contain a tag called "my-tag"
    IEnumerable<BlogPostPart> posts = _contentManager.Query(VersionOptions.Published, "BlogPost")
                                                   .Join<CommonPartRecord>()
                                                   .Where(cr => cr.Container == blog.Record.ContentItemRecord)
                                                   .Join<TagsPartRecord>()
                                                   .Where(tpr => tpr.Tags.Any(t => t.TagRecord.TagName == tag))
                                                   .WithQueryHints(new QueryHints().ExpandRecords<TagsPartRecord>().ExpandParts<TagsPart>())
                                                   .Slice(maxPosts)
                                                   .Select(ci => ci.As<BlogPostPart>());
    blogPosts.AddRange(posts);
}


来源:https://stackoverflow.com/questions/17559104/how-to-filter-related-content-parts-within-a-orchard-cms-query

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!