我在寻求帮助。我必须将我的 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 种调用解决方案:
- 直接SQL调用
- 调用 NamedQuery 和
- 通过 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/