我有以下两个实体:
public sealed class Parent
{
public long ParentId { get; set; }
public bool Deleted { get; set; }
public ISet<Child> Children { get; set; }
public Parent()
{
Children = new HashedSet<Child>();
}
}
和
public sealed class Child
{
public long ChildId { get; set; }
public bool Deleted { get; set; }
public Parent Parent { get; set; }
public Child()
{
}
}
使用映射文件:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="OperationalExcellenceDiary.DomainModels"
namespace="OperationalExcellenceDiary.DomainModels.Entities">
<class name="Parent" table="Parent" lazy="false">
<id name="ParentId" column="ParentId">
<generator class="native"/>
</id>
<set name="Children" inverse="false" cascade="all-delete-orphan" lazy="false">
<key column="ParentId"/>
<one-to-many class="Child"/>
</set>
<property name="Deleted" type="bool">
<column name="Deleted" default="0"/>
</property>
</class>
</hibernate-mapping>
和
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="OperationalExcellenceDiary.DomainModels"
namespace="OperationalExcellenceDiary.DomainModels.Entities">
<class name="Child" table="Child" lazy="false">
<id name="ChildId" column="ChildId">
<generator class="native"/>
</id>
<many-to-one name="Parent" class="Parent" column="ParentId" foreign-key="FK_Parent_Child" />
<property name="Deleted" type="bool">
<column name="Deleted" default="0"/>
</property>
</class>
</hibernate-mapping>
我希望所有未标记为“已删除”的父母及其子女以及未标记为“已删除”的父母
以下SQL查询就是这样做的:
select
Parent.*,
Child.*
from Parent
left outer join (
select *
from Child
where Child.Deleted = 0
) as Child
on Parent.ParentId = Child.ParentId
where Parent.Deleted = 0
如何将其转换为nHibernate查询?
我尝试过CreateSQLQuery:
IEnumerable<Parent> parents = session.CreateSQLQuery(@"
select
{Parent.*},
{Child.*}
from Parent
left outer join (
select *
from Child
where Child.Deleted = 0
) as Child
on Parent.ParentId = Child.ParentId
where Parent.Deleted = 0")
.AddEntity("Parent", typeof(Parent), LockMode.None)
.AddEntity("Child", typeof(Child), LockMode.None)
.List<Parent>();
但收到"The value "System.Object[]" is not of type "Parent" and cannot be used in this generic collection."
例外。
我试过HQL:
IEnumerable<Parent> parents = session.CreateQuery(@"
from Parent as parent
left outer join (
select *
from Child as child
where child.Deleted = :deleted
) as Child
on parent.ParentId = Child.ParentId
where parent.Deleted = 0")
.SetParameter("deleted", false)
.List<Parent>();
但收到"Exception of type 'Antlr.Runtime.NoViableAltException' was thrown."
例外。
我也尝试过CreateCriteria:
IEnumerable<Parent> parents = session.CreateCriteria<Parent>()
.Add(Restrictions.Eq("Deleted", false))
.CreateCriteria("Children", "children", NHibernate.SqlCommand.JoinType.LeftOuterJoin)
.Add(Restrictions.Eq("children.Deleted", false))
.SetResultTransformer(Transformers.DistinctRootEntity)
.List<Parent>();
但如果父母没有任何子女,则不会返回父母,这是错误的。
我还尝试了一个分离查询:
DetachedCriteria children = DetachedCriteria.For<Child>()
.SetProjection(Projections.Property("Parent.ParentId"))
.Add(Restrictions.Eq("Deleted", false));
IEnumerable<Parent> parents = session.CreateCriteria<Parent>()
.CreateAlias("Children", "child", NHibernate.SqlCommand.JoinType.LeftOuterJoin)
.Add(Subqueries.PropertyIn("ParentId", children))
.List<Parent>();
但这甚至可以从简单的检查中明确表示它不起作用......
有什么想法吗?
谢谢! :)
UPDATE \ FIX
好的,所以找到了一个解决方法\ fix ...虽然不是我想的最优雅的解决方案。
我在我的Parent
映射文件中添加了一个过滤器,并将条件添加到我的one-to-many
关系中。
Parent映射文件现在如下所示:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="OperationalExcellenceDiary.DomainModels"
namespace="OperationalExcellenceDiary.DomainModels.Entities">
<class name="Parent" table="Parent" lazy="false">
<id name="ParentId" column="ParentId">
<generator class="native"/>
</id>
<set name="Children" inverse="false" cascade="all-delete-orphan" lazy="false">
<key column="ParentId"/>
<one-to-many class="Child"/>
<filter name="ChildIsDeleted" condition="Deleted = 0" />
</set>
<property name="Deleted" type="bool">
<column name="Deleted" default="0"/>
</property>
</class>
<filter-def name="ChildIsDeleted"></filter-def>
</hibernate-mapping>
现在将过滤掉未删除的子项。
当我执行查询时,我只启用新创建的过滤器:
session.EnableFilter("ChildIsDeleted");
IEnumerable<Parent> parents = session.CreateCriteria<Parent>()
.Add(Restrictions.Eq("Deleted", false))
.List<Parent>();
它仍然不会创建派生表,但会返回所需的结果。因此,即使所有Children
都标记为已删除,但Parent
未标记为Parent
,仍会返回{{1}}。