【问题标题】:Orchard CMS ContentQuery with N-to-N relation具有 N 对 N 关系的 Orchard CMS ContentQuery
【发布时间】:2014-12-20 13:41:52
【问题描述】:

在我的项目中,我在 OrchardProject 网站上使用 this tutorial 实现了记录之间的 N 对 N 关系。我有 2 个部分:MaterialPart & CategoryPart 和关联记录。

材质部分

public class MaterialPartRecord : ContentPartRecord {
    public MaterialPartRecord() {
        Categories = new List<ContentMaterialCategoryRecord>();
    }
}

public class MaterialPart : ContentPart<MaterialPartRecord> {
    public IEnumerable<CategoryPartRecord> Categories {
        get { return Record.Categories.Select(cmcr => cmcr.CategoryPartRecord); }
    }
}

CategoryPartRecord

public class CategoryPartRecord : ContentPartRecord {
    ...
}

public class CategoryPart : ContentPart<CategoryPartRecord> {
    ...
}

关联记录:

public class ContentMaterialCategoryRecord {
    public virtual int Id { get; set; }
    public virtual MaterialPartRecord MaterialPartRecord { get; set; }        
    public virtual CategoryPartRecord CategoryPartRecord { get; set; }        

}

现在我需要选择链接到某个类别的MaterialItems。到目前为止,我有这种方法来提取它们。它有效,但我不确定这是正确的方法。

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));        // < ---- ?    
}

所以我的问题是:为所需类别选择 materials 的正确方法是什么,这会产生最佳 SQL 查询,因为我们只需要将 inner join 关联记录表与所需的 CategoryPartRecord_Id 字段值联系起来。

谢谢!

【问题讨论】:

  • 您能解释一下为什么不使用分类法吗?
  • @BertrandLeRoy 我已经在上一个关于面包屑的问题中解释过 :) 你总是说分类法,因为它是所有任务的灵丹妙药。
  • 好吧,如果我不知道谁在我回答的所有问题上说了些什么,请原谅我,尤其是在没有链接的情况下。当有明确的用例时,我总是会提出分类法。您正在重新实现类别,这正是分类法的设计目的。那你为什么不使用它们呢?

标签: c# nhibernate orchardcms orchardcms-1.8


【解决方案1】:

如果 M : N 带有配对对象,我们可以使用 QueryOver 和子查询。最大的好处是,我们收到了一组简单的材料项,我们可以将其用于分页(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 是我想说的 NHibernate 最原生的方式。无论如何,按类别过滤的原则 - 子查询和加载材料的主查询将保持不变。只有一个 SQL Select 调用

【讨论】:

  • 感谢您的回答!据我了解,这是在没有所有这些 Orchard CMS ContentQueries 等内容的情况下使用 NHibernate 的直接方式?
  • 是的。 ;) 不确定这是否是您想要的,抱歉,不知道 Orchard ......但我想说的是 NHibernate 方式是这样的;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-16
  • 2011-11-08
相关资源
最近更新 更多