C# 具有N-to-N关系的Orchard CMS ContentQuery

C# 具有N-to-N关系的Orchard CMS ContentQuery,c#,nhibernate,orchardcms,orchardcms-1.8,C#,Nhibernate,Orchardcms,Orchardcms 1.8,在我的项目中,我实现了OrchardProject网站上使用的记录之间的N对N关系。我有两个部分:材料零件和分类零件和协会记录 重要部分 现在我需要选择链接到特定类别的MaterialItem。到目前为止,我有这个方法来提取它们。这是可行的,但我不确定这是否是正确的方法 public IEnumerable<MaterialPart> GetMaterialsByCategory(int catId) { var cs = new CategoriesService(_oS

在我的项目中,我实现了OrchardProject网站上使用的记录之间的N对N关系。我有两个部分:材料零件和分类零件和协会记录

重要部分

现在我需要选择链接到特定类别的MaterialItem。到目前为止,我有这个方法来提取它们。这是可行的,但我不确定这是否是正确的方法

public IEnumerable<MaterialPart> GetMaterialsByCategory(int catId) {

    var cs = new CategoriesService(_oServices);

    CategoryPartRecord cat = cs.GetItem(catId).Record;

    return _oServices.ContentManager
             .Query(VersionOptions.Latest, _contentType)
             .Join<CommonPartRecord>()
             .OrderByDescending(cpr => cpr.PublishedUtc);
             .List()
             .Where(ci => ci.IsPublished())
             .Select(ci => ci.As<MaterialPart>())
             .Where(mp => mp.Categories.Contains(cat));        // < ---- ?    
}
所以我的问题是:选择所需类别的材料的正确方法是什么,这会产生最佳的SQL查询,因为我们只需要将关联的记录表与所需CategoryPartRecord_Id字段值进行内部联接


萨克斯

在M:N与配对对象的情况下,我们可以使用QueryOver和subquery。最大的好处是,我们收到了一组简单的材料项,可以用于分页Take、Skip

var session = ... // get curretn session

CategoryPartRecord category = null;
ContentMaterialCategoryRecord pair = null;
MaterialPartRecord material  = null;

var subquery = QueryOver.Of<ContentMaterialCategoryRecord>(() => pair)

    // now we will join Categories to be able to filter whatever property
    .JoinQueryOver(() => pair.CategoryPartRecord, () => category)

    // here is the filter
    // there could be IN, >= <= ...
    .Where(() => category.ID == 1)
    // or
    .WhereRestrictionOn(c => c.category.ID).IsIn(new[] {1, 2, 3})
    ...

    // now we will return IDs of the Material we are interested in
    .Select(x => pair.MaterialPartRecord.Id);


// finally the clean query over the Materials... 
var listOfUsers = session.QueryOver<MaterialPartRecord>(() => material  )
    .WithSubquery
        .WhereProperty(() => material.Id)
        .In(subquery)
    // paging
    .Take(10)
    .Skip(10)
    .List<MaterialPartRecord>();
因此,这将生成最有效的SQL脚本,其中包含一个子选择和从材质表中清除选择


注意:即使使用LINQ也可以完成类似的工作。但QueryOver是我所说的最土生土长的方式。无论如何,按类别筛选的principe子查询和加载物料的主查询将保持不变。只有一个SQL Select呼叫

谢谢您的回答!据我所知,这是一种直接使用NHibernate的方法,而不需要所有这些内容;不知道这是不是你想要的,对不起,不知道果园。。。但我要说的是,尼伯内特的方式就是这样;你能解释一下你为什么不使用分类法吗?@BertrandLeRoy我在前面的问题中已经解释过面包屑:你总是说分类法,因为它是所有任务的灵丹妙药。好吧,如果我不知道是谁对我回答的所有问题说了什么,特别是如果没有与它们相关联的话,请原谅。当有明确的用例时,我总是提出分类法。您正在实现类别,这正是分类法的设计目的。那你为什么不用呢?
public class ContentMaterialCategoryRecord {
    public virtual int Id { get; set; }
    public virtual MaterialPartRecord MaterialPartRecord { get; set; }        
    public virtual CategoryPartRecord CategoryPartRecord { get; set; }        

}
public IEnumerable<MaterialPart> GetMaterialsByCategory(int catId) {

    var cs = new CategoriesService(_oServices);

    CategoryPartRecord cat = cs.GetItem(catId).Record;

    return _oServices.ContentManager
             .Query(VersionOptions.Latest, _contentType)
             .Join<CommonPartRecord>()
             .OrderByDescending(cpr => cpr.PublishedUtc);
             .List()
             .Where(ci => ci.IsPublished())
             .Select(ci => ci.As<MaterialPart>())
             .Where(mp => mp.Categories.Contains(cat));        // < ---- ?    
}
var session = ... // get curretn session

CategoryPartRecord category = null;
ContentMaterialCategoryRecord pair = null;
MaterialPartRecord material  = null;

var subquery = QueryOver.Of<ContentMaterialCategoryRecord>(() => pair)

    // now we will join Categories to be able to filter whatever property
    .JoinQueryOver(() => pair.CategoryPartRecord, () => category)

    // here is the filter
    // there could be IN, >= <= ...
    .Where(() => category.ID == 1)
    // or
    .WhereRestrictionOn(c => c.category.ID).IsIn(new[] {1, 2, 3})
    ...

    // now we will return IDs of the Material we are interested in
    .Select(x => pair.MaterialPartRecord.Id);


// finally the clean query over the Materials... 
var listOfUsers = session.QueryOver<MaterialPartRecord>(() => material  )
    .WithSubquery
        .WhereProperty(() => material.Id)
        .In(subquery)
    // paging
    .Take(10)
    .Skip(10)
    .List<MaterialPartRecord>();