Hibernate多态查询

时间:2009-06-12 03:07:59

标签: java hibernate hql polymorphism

我有两个类,Person和Company,来自另一个类Contact。它们在两个表(Person和Company)中以多态形式表示。简化的类看起来像这样:

public abstract class Contact {

  Integer id;

  public abstract String getDisplayName();

}

public class Person extends Contact {

  String firstName;
  String lastName;

  public String getDisplayName() {
    return firstName + " " + lastName;
  }

}

public class Company extends Contact {

  String name;

  public String getDisplayName() {
    return name;
  }

}

问题是我需要查询查找包含某个字符串的displayName的所有联系人。我不能使用displayName进行查询,因为它不是任何一个表的一部分。关于如何进行此查询的任何想法?

3 个答案:

答案 0 :(得分:4)

因为你在Java类中进行连接,所以Hibernate无法真正帮助你解决这个问题,对不起。它根本无法看到你在这个方法中做了什么,因为它实际上与持久性无关。

解决方案取决于您如何映射这些类的继承:

如果是每层次表,您可以使用以下方法:为条件查询编写SQL where子句,然后使用case语句:

s.createCriteria(Contact.class)
 .add(Restrictions.sqlRestriction("? = case when type='Person' then firstName || ' '|| lastName else name end"))
 .list();

如果是table per-concrete-subclass,那么你最好编写两个查询(因为这就是Hibernate无论如何都要做的)。

答案 1 :(得分:2)

您可以在Contact表格中创建一个包含相应displayName的新列,您可以通过Hibernate Interceptor填充该列,以便它自动包含正确的字符串。

替代方案是有两个查询,一个用于Person,一个用于Company表,每个查询包含相应的搜索逻辑。您可能必须使用本机查询来实现通过LIKE查询查找连接字符串(我不是HQL专家,但很可能)。

如果你有大表,你应该考虑全文索引,因为LIKE '%...%'查询需要全表扫描,除非你的数据库支持全文索引。

答案 2 :(得分:1)

如果将displayName更改为映射属性(设置为公司中的名称列,并设置为类似于最后一个||''|| last in Person),则可以查询Contract和Hibernate将同时运行两个查询现在有一个displayName。您将获得两个列表的列表,一个包含公司,一个包含人员,因此您必须将它们合并在一起。我认为您需要通过Contract的完整包名来查询,或者设置一个typedef来告诉Hibernate。