postgresql - Hibernate:具有递归深度搜索的存储过程:映射/输出问题

标签 postgresql hibernate stored-procedures postgresql-9.4

我在寻求帮助。我必须将我的 Postgres 9.4 数据库 (DB) 映射到 Hibernate 5.2,当然这是一项学习任务。最大的问题是,我对 Hibernate、Java 和编码本身一窍不通 XD

这是一个 SozialNetwork 数据库。用 Hibernate 映射数据库做得很好。 现在我应该映射一个存储的产品。这个 Produce 应该找到两个人之间的最短友谊路径。在 Postgres 中,产品工作正常。

这是相关的数据库表: 对于个人:

CREATE TABLE Person (
 PID            bigint      NOT NULL,
 firstName      varchar(50) DEFAULT NULL,
 lastName       varchar(50)     DEFAULT NULL,
 (some more...)
 PRIMARY KEY (PID)
);

对于人与人之间的关系:

CREATE TABLE Person_knows_Person (
 ApID           bigint  NOT NULL,
 BpID           bigint  REFERENCES Person (PID) (..)
 knowsCreationDate  timestamp,
 PRIMARY KEY (ApID,BpID));

简而言之,就是存储的产品:

CREATE OR REPLACE FUNCTION ShortFriendshipPath(pid bigint, pid2 bigint)
  RETURNS TABLE (a_pid bigint, b_pid bigint, depth integer, path2 bigint[], cycle2 boolean)
AS $$
BEGIN
RETURN QUERY 
SELECT * FROM (
   WITH RECURSIVE FriendshipPath(apid, bpid, depth, path, cycle) AS(
   SELECT pkp.apid, pkp.bpid,1,
          ARRAY[pkp.apid], false
     FROM person_knows_person pkp 
     WHERE apid=$1 --OR bpid=$1
 UNION ALL
 SELECT pkp.apid, pkp.bpid, fp.depth+1, path || pkp.apid,
        pkp.apid = ANY(path)
    FROM person_knows_person pkp, FriendshipPath fp
    WHERE pkp.apid = fp.bpid AND NOT cycle)
SELECT * 
   FROM FriendshipPath WHERE bpid=$2) AS OKOK
UNION
SELECT * FROM (
   WITH RECURSIVE FriendshipPath(apid, bpid, depth, path, cycle) AS(
   SELECT pkp.apid, pkp.bpid,1,
   ARRAY[pkp.apid], false
   FROM person_knows_person pkp 
   WHERE apid=$2 --OR bpid=$1
UNION ALL
SELECT pkp.apid, pkp.bpid, fp.depth+1, path || pkp.apid,
       pkp.apid = ANY(path)
   FROM person_knows_person pkp, FriendshipPath fp
   WHERE pkp.apid = fp.bpid AND NOT cycle)
SELECT * 
FROM FriendshipPath WHERE bpid=$1)   AS YOLO
 ORDER BY depth ASC LIMIT 1;
END;
$$ LANGUAGE 'plpgsql' ;

(抱歉代码太多,但它是双向的,在我发布一些复制+减少错误之前^^) 例如 Postgre 中的调用:

 SELECT * FROM ShortFriendshipPath(10995116277764, 94);

给我这个输出: enter image description here

我使用互联网寻求帮助并找到 3 种调用解决方案:

  1. 直接SQL调用
  2. 调用 NamedQuery 和
  3. 通过 XML 映射

(最喜欢的 here ) 我都失败了 XD

我最喜欢1。解决方案 在 session 中使用此调用:

Session session = HibernateUtility.getSessionfactory().openSession();
  Transaction tx = null;
  try {
    tx = session.beginTransaction();
    System.out.println("Please insert a second PID:"); 
    Scanner scanner = new Scanner(System.in);
    long pid2 = Long.parseLong(scanner.nextLine());
// **Insert of second ID*/
    Query query2 = session.createQuery("FROM " + Person.class.getName() + " WHERE pid = :pid ");
    query2.setParameter("pid", pid2);
    List<Person> listB = ((org.hibernate.Query) query2).list();
    int cnt1 = 0;
    while (cnt1 < listB.size()) {
        Person pers1 = listB.get(cnt1++);
        pid2 = pers1.getPid();
    }
// Query call directly:
    Query querySP = session.createSQLQuery("SELECT a_pid,path2 FROM ShortFriendshipPath(" + pid + "," + pid2 + ")");
    List <Object[]> list = ((org.hibernate.Query) querySP).list();
     for (int i=0; i<list.size();i++){
         Personknowsperson friendship = (Personknowsperson)result.get(i);
     } 
    } catch (Exception e) { (bla..)}
    } finally { (bla....) }

比我得到以下错误:

javax.persistence.PersistenceException: org.hibernate.MappingException: No Dialect mapping for JDBC type: 2003 (..blabla...)

我明白为什么。因为我的输出不是 Personknowsperson 类型。我找到了答案:我不得不说 Hibernate 的正确格式是什么。并且应该使用“UserType”。所以我试图找到一些关于我如何创建我的 UserType 的解释。但我什么也没发现,我明白了。第二个问题:我不确定我应该为 bigint[] (path2) 使用什么。你看我是专家-.-

于是我有了尝试3.solution 的想法。但我遇到的第一个问题是我应该在哪里写 xml 的东西。因为我的输出没有表格。所以我在 .cfg.xml 中尝试,但 Hibernate 说

由以下原因引起:java.lang.IllegalArgumentException:org.hibernate.internal.util.config.ConfigurationException:无法在 RESOURCE hibernate.cfg.xml 中的行号 -1 和列 -1 处执行解码。消息:cvc-complex-type.2.4.a: Ungültiger Content wurde beginnend mit Element 'sql-query' gefunden。 '{some links}' wired erwartet。

翻译:

invalid content found starts with 'sql-query'

现在我很紧张。并问你。 有人可以解释我必须做什么以及我做错了什么(请假人)。如果需要更多代码(java 类或其他),请告诉我。也欢迎批评编码,因为我想改进 =)

最佳答案

好吧,我不是 postgressql 专家,不是 hibernate 专家,也不是 java 专家。 (我正在使用 C#、SQL Server、NHibernate 等等......)我仍然会尝试给你一些提示。

您可能可以使用 addXyz 方法设置列的类型:

Query querySP = session
    .createSQLQuery("SELECT * FROM ShortFriendshipPath(...)")
    .addScalar("a_pid", LongType.INSTANCE)
    ...
    // add user type?

您需要为数组创建一个用户类型。我不知道如何以及是否可以将它添加到查询中。参见 this answer在这里。

您还可以添加整个实体:

 Query querySP = session
    .createSQLQuery("SELECT * FROM ShortFriendshipPath(...)")
    .addEntity(Personknowsperson.class)
    ...;

希望它带上对应映射文件的映射定义,可以在里面指定用户类型。

通常获得一个简单的值列表要容易得多,我的意思是数组中每个不同的值都有一个单独的行。像这样:

代替

1 | 2 | (3, 4, 5) | false

你会得到:

1 | 2 | 3 | false
1 | 2 | 4 | false
1 | 2 | 5 | false

这似乎是非规范化的,但实际上是您构建关系数据的方式。

通常:在将 id 之类的东西传递给查询时使用参数。

 Query querySP = session
    .createSQLQuery("SELECT * FROM ShortFriendshipPath(:pid1, :pid2)")
    .setParameter("pid1", pid1)
    .setParameter("pid2", pid2)
    ...

关于postgresql - Hibernate:具有递归深度搜索的存储过程:映射/输出问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39392409/

相关文章:

java - HQL diff 2 以天为单位的日期

hibernate - jpa实体不更新数据库中的关系操作

php - 我可以在php中调用两个过程吗?

sql-server - Visual Studio 2013 CLR存储过程

python - Django:基于JSONField动态设置模型实例属性

ruby-on-rails - 如何在 Rails 中查找列值 = [给定数组] 的记录

python - 向 Django 数据库添加元素

hibernate :未映射的类关联异常

hibernate - 使用@Where 子句映射@OneToOne

oracle - 将数据从一张表复制到另一张表的存储过程