仅在使用Criteria查询时检索特定列?

时间:2009-03-30 03:26:47

标签: nhibernate

我正在为我们公司正在进行的项目提供NHibernate,我想知道NHibernate是否可以优化,以便在使用Criteria查询语言时只检索表上的特定列。

例如。假设我有一个包含30列的表,并使用NHibernate映射到一个对象,该对象是针对该表的1对1匹配。但是,对于系统的特定功能,我只关心其中两个列。

现在,我知道我可以使用HQL并执行CreateQuery来完成此任务,但这需要为我想要有选择地检索的每个字段组合创建一个构造函数。从维护的角度来看,这可能是一个巨大的痛苦,因为我不会在运行时之前捕获缺少的构造函数。

我喜欢Criteria查询语言,因为它生成参数化SQL而不是来自HQL的直接SQL查询。我看到有一个“排除”模型不包括某些列,但在大多数情况下,我将包括更多列而不是排除。

感谢下面的评论,我调查了预测,这对我来说仍然不是一个理想的情况。使用以下内容时:

var list = session
    .CreateCriteria(typeof (Task))
    .SetProjection(Projections
                       .ProjectionList()
                       .Add(Projections.Property("Id")))
    .List();

我最后得到的变量list就是整数,我更喜欢拥有完整的Task对象,但所有字段都设置为默认值。这甚至可能吗?到目前为止,我所看到的一切都说没有。

5 个答案:

答案 0 :(得分:34)

是的,您可以使用投影对条件查询执行此操作。只需投影您想要使用的属性,只有那些将包含在已编译查询的select子句中。

http://nhibernate.info/doc/nh/en/index.html#querycriteria-projection

更新以进行修改

有几种方法可以实现这一目标,但有一些限制。 1)NHibernate方式。

var list = session.CreateCriteria(typeof (Task))
.SetProjection(Projections.ProjectionList()
                   .Add(Projections.Property("Name"), "Name")
                   .Add(Projections.Property("ID"), "ID")
)
.SetResultTransformer(Transformers.AliasToBean(typeof (Task)))
.List();

只需将属性名称指定为投影的别名,AliasToBean转换器就会将这些投影映射到实际的类。此方法的限制是您映射的任何属性必须在POCO类中具有setter,这可以是受保护的setter,但它必须具有setter。

您也可以使用linq以稍微不同的方式执行此操作

var list = session.CreateCriteria(typeof (Task))
.SetProjection(Projections.ProjectionList()
                   .Add(Projections.Property("Name"))
                   .Add(Projections.Property("ID"))
)
.List<IList>()
.Select(l => new Task() {Name = (string) l[0], ID = (Guid) l[1]});

这只是使用linq将输出的索引列表映射到Task类的新实例。与上述相同的限制适用,除了这一点有点严重,因为映射的所有属性都必须有一个公共setter,因为这是linq用来填充对象的。

我希望这会对你有所帮助。

答案 1 :(得分:5)

响应您的修改: 据我所知,这是不可能的。

但是,你可以做的是创建一个NHibernate所知的类,它只包含你感兴趣的属性。

例如,一个'TaskView'类,它只包含'Task'类的某些属性 您必须在hbm.xml文件中“导入”TaskView类,以便NHibernate知道此类(请参阅导入映射)。
然后,您可以使用Projection将“Task”转换为TaskView实例。当您查看NHibernate生成的查询时,您将看到它只会检索填充TaskView类所需的列。

像我在这里发布的东西: NHibernate and Collection Counts

答案 2 :(得分:0)

我不确定这是否适合您的目的,但这只是一个建议:如果查询最终成为总是使用的东西,您可以为它创建一个SQL视图,然后针对View创建一个映射文件。

NHibernate会像处理任何表一样处理View,尽管CRUD操作当然会成为数据完整性问题的一个问题。

答案 3 :(得分:0)

您是否尝试过设置默认构造函数来设置默认值?由于这是应用程序方面的问题,因此您需要解决。顺便说一下,为什么每个排列都需要一个构造函数? Hibernate将使用all参数构造函数或无参数构造函数然后使用setter,因此不需要执行所有这些工作。实际上它可以做的更多,如果我没记错,如果通过字节码操作魔术正确配置它甚至可以设置所有没有setter的私有字段。

答案 4 :(得分:-1)

我问了一个类似的问题,NHibernate似乎缺乏自创建SQL以来应用程序使用的最常见功能。只能选择一些列的功能。这真是老生常谈,如果我参与了这个项目,我会拒绝任何要求你跳过篮筐并且颠倒过来的逻辑,只是为了选择领域。即使有答案,我发现数小时的研究对于如此简单的事情来说太复杂了。我知道它可以在Nhibernate的linq提供程序中使用投影,但对于极其复杂的查询,它是不可能的,所以只选择特定的字段。无论是全部还是你必须开始创建不是原始的DTO /模型,在我看来不应该重复,因为用户只需要更少的记录。基于常规sql查询(不是linq)的排除/包含列表是必须的。我希望这些ORM首先做最基本的事情。如果未在数据库的结果集中返回字段,则忽略填充模型。我希望有人可以提供一个简单的解决方案/黑客/解决方法。