如何在NHibernate QueryOver查询中选择和使用值对象的集合

时间:2011-08-14 21:10:54

标签: c# .net nhibernate queryover

我有一个简单的模型,包含一个使用引用对象引用一篇或多篇文章的文档(这是因为在域中,我们不拥有文章,所以我们只能引用它们。)

我正在尝试编写一个列出文档的查询,打印ID以及一个由逗号分隔的文章编号列表组成的字符串。例如:

ID ARTICLES
------------------
1  ACC, PE2,
2  ER0, AQ3, FEE
3  PE2

我的问题是选择以逗号分隔的列表。

以下是域类:

// The Entity class has an Id property.
public class Document : Entity
{
    public virtual IEnumerable<ArticleReference> ArticleReferences { get; set; }
    public virtual DateTime ReceiveDate { get; set; }
}

// The ValueObject does not have an Id property ofcourse.
public class ArticleReference : ValueObject
{
    public virtual string ArticleNumber { get; set; }
    public virtual string ArticleName { get; set; }
}

文章引用是一个值对象,因此它没有自己的ID。

这是表示结果列表中项目的视图模型:

public class DocumentListItemModel
{
    public int Id { get; set; }
    public string ArticleNumbers { get; set; }
    public string ReceiveDate { get; set; }
}

这是我到目前为止提出的查询类:

public class DocumentQuery
{
    public IList<DocumentListItemModel> ExecuteQuery()
    {
        IntermediateModel model = null;
        ArticleReference articleReferenceAlias = null;

        return Session
            .QueryOver<Document>()
            .JoinAlias(n => n.ArticleReferences, () => articleReferenceAlias);
            .SelectSubQuery(
                QueryOver.Of<ArticleReference>(() => articleReferenceAlias)
                    // There is no way of matching references to documents from a domain
                    // point of view since the references are value objects and
                    // therefore don't have an ID.
                    .Where(n => ...)
                    .Select(q => articleReferenceAlias.Number))
                .WithAlias(() => model.ArticleNumbers)
            .TransformUsing(Transformers.AliasToBean<IntermediateModel>());
            .Future<IntermediateModel>()
            .ToList()
            .Select(n =>
                new DocumentListItemModel()
                {
                    Id = n.Id,
                    ArticleNumbers = string.Join(", ", n.ArticleNumbers.OrderBy(p => p)),
                    ReceiveDate = n.ReceiveDate.ToString("d", CultureInfo.CurrentCulture)
                })
            .ToList();
    }

    private class IntermediateModel
    {
        public int Id { get; set; }
        public IEnumerable<string> ArticleNumbers { get; set; }
        public DateTime ReceiveDate { get; set; }
    }
}

正如您所看到的,我无法表达.Where语句,因为从域的角度来看无法匹配对文档的引用。引用是值对象,因此没有ID。

问题是:如何修复查询以正确选择文章编号列表,以便我可以在string.Join语句中使用它来制作以逗号分隔的字符串?

2 个答案:

答案 0 :(得分:1)

我认为你的字面意思是对价值对象的定义。将代理标识符(标识列,Guid等)分配给值对象不会使其成为值对象。它是value object因为它的平等是基于它的价值而不是它的身份。这并不要求值对象不能具有标识,并且在实践中它几乎总是必须具有。

您的应用程序显然必须能够将Document链接到一组ArticleReferences,并且最好的方法是通过向ArticleReference添加ID。

答案 1 :(得分:0)

我设法解决了这个问题。这就是我最终的结果:

public IList<DocumentListItemModel> ExecuteQuery()
{
    ArticleReference articleReferenceAlias = null;

    return Session
        .QueryOver<Document>()
        .JoinAlias(n => n.ArticleReferences, () => articleReferenceAlias,
            JoinType.LeftOuterJoin)
        .SelectList(list => list
            .Select(n => n.Id)
            .Select(n => articleReferenceAlias.Number))
        .List<object[]>()
        .Select(x => new
        {
            Id = (int)x[0],
            ArticleNumber = (string)x[1]
        })
        .GroupBy(n => n.Id).Select(n =>
        {
            return new DocumentListItemModel
            {
                Id = n.First().Id,
                ArticleNumbers = string.Join(", ", n.Select(p => p.ArticleNumber))
            };
        }).ToList();
    }
}

我不能再使用alias-to-bean转换器了,因为它无法处理集合属性。这就是解决方案具有GroupBy的原因,它整合了行,将文章编号聚合成一个字符串。