我正在使用NH Criteria检索实体并将选择性字段投影到自定义类(有点像将数据投影到ViewModel上以便在MVC视图上显示)。
使用ProjectionList很容易:
var emailCriteria = mSession.CreateCriteria<Email>();
emailCriteria.SetProjection(
Projections.ProjectionList()
.Add(Projections.Property("Subject"), "Subject")
);
emailCriteria.SetResultTransformer(Transformers.AliasToBean<EmailDataModel>());
var result = emailCriteria.List<EmailDataModel>();
但是,我的实体包含一个集合,我也希望将它带回来,并将其作为集合投影到我的自定义类中。
我的域模型看起来(简化形式)如下:
public class Email {
public string Subject
public List<EmailAttachment> Attachments
etc...
}
public class EmailAttachment {
public UploadedFile File
}
public class UploadedFile {
public string Filename
public UploadedFileData Data
}
public class UploadedFileData {
public byte[] Data
}
这是我要投射到的“数据模型”类:
public class EmailDataModel {
public string Subject
public List<EmailAttachmentDataModel> Attachments
}
public class EmailAttachmentDataModel {
public string Filename
public byte[] Data
}
现在我知道这些模型看起来非常相似,你会认为“重点是什么?”,但那是因为我简化了它们。很高兴能够将我的域对象压缩成方便的数据模型。
我的一个大问题是弄清楚如何从我的子对象(在本例中为UploadedFile.Filename和UploadedFileData.Data)深入访问必要的字段,并将它们作为EmailAttachmentDataModel集合投影到我的EmailDataModel上。
我在线阅读了许多讨论访问子集合的文章 - 使用EmailCriteria.CreateAlias或EmailCriteria.CreateQuery - 但我没有找到任何解释如何将子集合作为集合进行投影的文章。
我希望对于有兴趣修改NH Criteria查询的人来说,这将是一个有用的练习。
答案 0 :(得分:5)
好的,我想我已经解决了升级到NHibernate 3并使用QueryOver的问题。这是我的代码现在的样子:
//Declare entities
Email email = null;
EmailAttachment attachment = null;
UploadedFile file = null;
Byte[] fileData = null;
//Select data from parent and child objects
var results = mSession.QueryOver<QueuedEmail>(() => email)
.JoinAlias(() => email.Attachments, () => attachment, JoinType.LeftOuterJoin)
.JoinAlias(() => attachment.File, () => file, JoinType.LeftOuterJoin)
.JoinAlias(() => file.Data, () => fileData, JoinType.LeftOuterJoin)
.TransformUsing(Transformers.DistinctRootEntity)
.List<Email>()
//Loop through results projecting fields onto POCO
.Select(x => new EmailDataModel()
{
Id = x.Id,
Body = x.Body,
AttachmentCount = x.Attachments.Count(),
FromAddress = x.FromAddress,
//Loop through child collection projecting fields onto POCO
Attachments = x.Attachments.Select(attach => new EmailAttachmentDataModel()
{
Data = attach.File.Data.Data,
Filename = attach.File.Filename,
Id = attach.Id
}).ToArray() //NB Now projecting this collection as an array, not a list
}).ToArray();
就是这样。我们的结果是一个扁平的类,它包含我们需要的数据,以及一组附件(每个附件只包含我们数据结构中的两个字段 - 很好地展平)。
你为什么要这样做?
它通过展平到我真正想要的字段来简化结果。
我的数据现在安全地封装在一个可以传递的类中,而不用担心意外更新我的数据(如果你只是传回NH数据实体就可能发生这种情况)。
最后(也是最重要的),因为上面的代码只生成一个SELECT语句。如果我坚持使用我原来的Criteria查询,它会为每一行生成一个SELECT,并为链中的下一个孩子生成更多。如果您处理的是小数字,那就没问题,但如果您可能会返回数千行,那就不行了(正如我将在这个例子中那样 - 它是电子邮件引擎的网络服务)
我希望这对任何希望进一步深入NHibernate查询的人都有用。就个人而言,我很高兴我现在可以继续我的生活!