如何使用nHibernate中的一个子集筛选项目

本文关键字:一个 子集 筛选 项目 nHibernate 何使用 | 更新日期: 2023-09-27 18:29:33

我有一个对象,看起来如下。。。

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping namespace="test" assembly="test" xmlns="urn:nhibernate-mapping-2.2">
<class name="Person" table="`Person`">
        <id name="ItemId" access="property" column="`ItemId`">
            <generator class="native" />
        </id>
        <property name="Name" column="`A`" />
        <property name="Age" column="`B`" />
        <set name="Email" inverse="true">
            <key column="`Name`" />
            <one-to-many class="EmailClass" />
        </set>
    </class>
</hibernate-mapping>

我想做一个nHibernate查询,通过他们的电子邮件地址来过滤这些记录

我试过一些类似的东西。。

var childCriteria = QueryOver.Of<EmailClass>().Where(c => c.EmailAddress.ToString().IsLike("%" + strSearch + "%")).Select(c => c.EmailID);
var query = session.QueryOver<Person>().WithSubquery.WhereExists(childCriteria).Future();

我显然做错了什么。问题是,是否可以搜索数据对象的子集?还是对我来说,直接搜索子表然后找到其父表更好?

如何使用nHibernate中的一个子集筛选项目

我想你差不多到了。

I。先映射的一些注意事项。。。

首先,我假设EmailClassPerson也有关系(因为在DB级别上这是双向关系)

public class EmailClass 
{
    ...
    public virtual Person Person { get; set; } // inverse mapping
}

这是合乎逻辑的,因为这个DB关系无论如何都是存在的。它已经被表示为一个名为Email的人的<set>。而且应该也是必须的,因为我们使用了inverse="true",它期望双向映射。。。

这也让我对地图产生了争议。你确定吗,这个映射是正确的:

<class name="Person" ...
    // KEY column of this entity is ItemId (seems to be int)
    <id name="ItemId" column="`ItemId`" ...
    ...
    <set name="Email" inverse="true">
        // this mapping says: NHibernate, try to find the value
        // of the ItemId in the Person table
        // in the column Name of the table EmailClass ... ?
        <key column="`Name`" />
        ...
        // would expect
        <key column="ItemId" /> // column inside of EmailClass table

我想说,通常,我们可以看到,用作根实体(Person)的键的<id>列名与用于集合映射的the <key>列相同。

因此,我希望EmailClass表应该像"ItemId""Person_ID"一样包含,这将保留对Person表的引用。

II。子查询过滤

现在让我们继续查询,希望以上情况成立。

// An Alias, to be used later
Person person = null;
var childCriteria = QueryOver
    .Of<EmailClass>()
    // more QueryOver native style of a LIKE expression
    .WhereRestrictionOn(c => c.EmailAddress).IsLike(strSearch, MatchMode.Anywhere)
    // trick here
    // if we want to use the EXISTS later
    // we need to join outer and inner query here
    // and that's a place for outer query ALIAS
    .Where(c => c.PersonId == person.ItemId)
    .Select(c => c.PersonId); // must select something...
var query = session
    // ALIAS expressing the outer query in action again
    .QueryOver<Person>(() => person)
    .WithSubquery
    .WhereExists(childCriteria)
    .Future();

所以,正如我们所看到的,几乎在那里。。。LIKE的QueryOver ish样式,以及基本的WHERE子句Person=EmailAddress.Person

III。映射。。。建议

请让我也提供一些我期望/建议的地图草案:

public class Person
{
    public virtual int ItemId { get; set;}
    public virtual IList<EmailClass> Emails { get; set; } // plural Emails
}
public class EmailClass 
{
    ...
    public virtual Person Person { get; set; } // inverse mapping
}

映射:

<class name="Person" ...
    ...
    <set name="Emails"        // plural
      cascade="all-delete-orphan" // usually makes sense to rely on NHibernate cascade
      batch-size="25"         // great feature improving 1 + N issue
      inverse="true"  >       // already used, improves WRITE operations sequence
      <key column="ItemId" /> // ItemId should column in the EmailClass table
        <one-to-many class="EmailClass" />
    </set>
</class>
<class name="EmailClass">
   <id ... 
   <many-to-one name="Person" column="ItemId" /> // the same column as in above <set
   ...

您可能想要:

session.QueryOver<Person>()
    .JoinQueryOver(p => p.EmailClass)
    .Where(e => e.EmailAddress.IsLike(strSearch, MatchMode.Anywhere))
    .Future<Person>();

这假定EmailClass.EmailAddressstring

这将生成如下所示的SQL:

select
    Person.* /* all person fields */
from
    Person
    inner join EmailClass on EmailClass.Name = Person.Name
where
    EmailClass.EmailAddress like '%strSearch%' /* your search term */