hibernate标准对一组元素进行包含/不包含限制

发布于 2024-10-15 01:05:30 字数 2760 浏览 3 评论 0原文

您好,我正在尝试将旧的基于 sql 的查询框架迁移到基于 Hibernate Criteria 的框架,目前我正在使用 Hibernate 版本 3.2。和 mysql v 5.0.54

我的问题是我想编写一个标准,返回所有在包含的元素集中没有具有值的 Bean。

bean 的 hibernate 配置文件摘要如下:

    <hibernate-mapping package="com.mydomain.beans">

       <typedef class="com.mydomain.dao.util.HibernateAgentOptionType" name="agent-option"/>

       <class name="Agent" table="agent">
           ...
           <set name="agentOptions" table="agent_options" fetch="join" lazy="true">
              <key column="agt_id"/>
              <element column="identifier" type="agent-option"/>
           </set>
       </class>
   </hibernate-mapping>

类文件类似于:

public class Agent {
   ...
   public Set<Option> getAgentOptions() {
      return agentOptions;
   }
   public void setAgentOptions(Set<Option> _agentOptions) {
      this.agentOptions = _agentOptions;
   }

   public enum Option {
      WEB_SITE_SYNDICATE ("web-site-syndicate"),
      RECEIVE_PREMIUM_ENQUIRIES ("receive-premium-enquiries"), 
      DO_NOT_SYNDICATE_ADS_TO_THIRD_PARTIES ("do-not-syndicate-ads-to-third-parties")
   }
}

我想检索所有在其 agentOptions 中没有选项“DO_NOT_SYNDICATE_ADS_TO_THIRD_PARTIES”的

代理 sql之前使用的是这样的:

SELECT agt.id 
FROM agent agt
WHERE agt.id NOT IN (
   SELECT sub_agt.id FROM agent sub_agt 
   JOIN agent_options AS agt_options ON agt_options.agt_id = sub_agt.id
   WHERE agt_options.identifier = 'do_not_syndicate_ads_to_third_parties'
)

我尝试过这个:

   ...
   Criteria crit = getHibernateSession().createCriteria(Agent.class);
   crit.addRestriction(Restriction.not(Restriction.in("agentOptions", noSyndicatedAds)));
   ...

它吐出错误的sql

我也尝试过使用别名:

   ...
   crit.createAlias("agentOptions", "agentOption");
   crit.add(Restrictions.not(Restrictions.in("agentOption", options)));
   ...

它抛出异常:

org.hibernate.MappingException:集合不是关联:Agent.agentOptions

最后我决定尝试一个强力的 sql 标准:

...
   crit.add(Restrictions.sqlRestriction(" {alias}.id not in " +
               "(select agt_sub.id " +
               "from agent agt_sub " +
               "join agent_options as agent_options_sub on agent_options_sub.agt_id = agt_sub.id " +
               "where agent_options_sub.identifier in (?)) ",
               Agent.Option.DO_NOT_SYNDICATE_ADS_TO_THIRD_PARTIES.getIdentifier(),
               new org.hibernate.type.StringType()
         ));
   ...

它有效,但看起来有点难看。

有谁知道是否有一种方法可以使用 std Criteria API 而不必求助于 sql。

任何帮助或建议将非常受欢迎。即使他们需要升级到更新版本的 Hibernate。

干杯 西蒙

Hi I'm trying to migrate my old sql based query framework to be Hibernate Criteria based, currently I'm using Hibernate version 3.2. and mysql v 5.0.54

My question is I want to write a criteria that returns all the Beans that do not have a value in a contained set of elements.

A summary of the hibernate config file for the bean is:

    <hibernate-mapping package="com.mydomain.beans">

       <typedef class="com.mydomain.dao.util.HibernateAgentOptionType" name="agent-option"/>

       <class name="Agent" table="agent">
           ...
           <set name="agentOptions" table="agent_options" fetch="join" lazy="true">
              <key column="agt_id"/>
              <element column="identifier" type="agent-option"/>
           </set>
       </class>
   </hibernate-mapping>

The class file is something like:

public class Agent {
   ...
   public Set<Option> getAgentOptions() {
      return agentOptions;
   }
   public void setAgentOptions(Set<Option> _agentOptions) {
      this.agentOptions = _agentOptions;
   }

   public enum Option {
      WEB_SITE_SYNDICATE ("web-site-syndicate"),
      RECEIVE_PREMIUM_ENQUIRIES ("receive-premium-enquiries"), 
      DO_NOT_SYNDICATE_ADS_TO_THIRD_PARTIES ("do-not-syndicate-ads-to-third-parties")
   }
}

I would like to retrieve all the agents who do not have the Option "DO_NOT_SYNDICATE_ADS_TO_THIRD_PARTIES" in their agentOptions

the sql that I was using for this previously was something like:

SELECT agt.id 
FROM agent agt
WHERE agt.id NOT IN (
   SELECT sub_agt.id FROM agent sub_agt 
   JOIN agent_options AS agt_options ON agt_options.agt_id = sub_agt.id
   WHERE agt_options.identifier = 'do_not_syndicate_ads_to_third_parties'
)

I've tried this:

   ...
   Criteria crit = getHibernateSession().createCriteria(Agent.class);
   crit.addRestriction(Restriction.not(Restriction.in("agentOptions", noSyndicatedAds)));
   ...

Which spits out bad sql

I've also tried this using aliases:

   ...
   crit.createAlias("agentOptions", "agentOption");
   crit.add(Restrictions.not(Restrictions.in("agentOption", options)));
   ...

Which throws an exception:

org.hibernate.MappingException: collection was not an association: Agent.agentOptions

Finally I decided to try a brute sql Criterion:

...
   crit.add(Restrictions.sqlRestriction(" {alias}.id not in " +
               "(select agt_sub.id " +
               "from agent agt_sub " +
               "join agent_options as agent_options_sub on agent_options_sub.agt_id = agt_sub.id " +
               "where agent_options_sub.identifier in (?)) ",
               Agent.Option.DO_NOT_SYNDICATE_ADS_TO_THIRD_PARTIES.getIdentifier(),
               new org.hibernate.type.StringType()
         ));
   ...

Which worked but seems a little bit ugly.

Does anyone know if there is a way using the std Criteria API without having to resort to sql.

Any help or suggestions would be very welcome. Even if they require upgrading to a more recent version of Hibernate.

Cheers
Simon

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

老旧海报 2024-10-22 01:05:30

将子查询构造为 DetachedCriteria,然后使用嵌套的 Restrictions 来实现 NOT IN。在你的情况下:

DetachedCriteria subquery = DetachedCriteria.forClass(Agent.class);
subquery.createAlias("agentOptions", "agentOption");
subbquery.add(Restrictions.eq("identifier", Agent.Option.DO_NOT_SYNDICATE_ADS_TO_THIRD_PARTIES.getIdentifier());
subquery.setProjection(Projections.property("agt_id")); // only return one field
crit.add(Restrictions.not(Restrictions.in("agt_id", subquery)));

Structure your subquery as a DetachedCriteria, and then use your nested Restrictions to achieve a NOT IN. In your case:

DetachedCriteria subquery = DetachedCriteria.forClass(Agent.class);
subquery.createAlias("agentOptions", "agentOption");
subbquery.add(Restrictions.eq("identifier", Agent.Option.DO_NOT_SYNDICATE_ADS_TO_THIRD_PARTIES.getIdentifier());
subquery.setProjection(Projections.property("agt_id")); // only return one field
crit.add(Restrictions.not(Restrictions.in("agt_id", subquery)));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文