如何使用 CriteriaUpdate 编写连接?

How to write Joins using CriteriaUpdate?

我想请求帮助我找到更新其他 table 中的外键值的解决方案。 例如:-

如果我们使用设备 Table

列是:- 设备名称 设备编号 显示名称 用户身份 房间号 已删除

其他 table 是房间 Table

列是:- roomName 房间号 房型 已删除

听说它看起来像一对多的关系。 即,一个房间将包含许多设备。

在上面两个tables roomId 是Rooms Table 中的主键,roomId 是Device Table 中的forgin key。 所以,听到我们想要的是我们必须更新 DeviceTable 中的 roomId。 我试过了,但是我找不到解决方案,我请求你们帮我解决这个问题。

数据库 tables 会像

Room Table(room_table)

room_id    room_name    room_type
1           ROOM1       ROOM_TYPE1
2           ROOM2       ROOM_TYPE2

Device Table like(device_table)
device_id     device_name    display_name    room_id
1              DEVICE1        DISPLAY1         1
2              DEVICE2        DISPLAY2         2

以上table希望大家理解

所以,现在我需要完成的任务是:- 我想更新设备 table 中的 roomId,即对于 DEVICE2,我们必须将 roomId 1 更新为 roomId 2,如下所示。

Device Table like(device_table)
device_id    device_name   display_name    room_id
1             DEVICE1       DISPLAY1         1
2             DEVICE2       DISPLAY2         2

为此,我编写了 java 代码,例如:-

    @Entity
    @Table(name = "device_table")
    public class Device {
        @Id
        @Column(name = "device_id")
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private int deviceId;
        @Column(name = "device_name")
        private String deviceName;
        @Column(name = "display_name")
        private String dispalyName;
        @ManyToOne(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
        //private List<Room> roomList = new ArrayList<>();
        @JoinColumn(name = "ROOM_ID")
        private Room roomList; 
         //setters & getters
    }

        @Entity
        @Table(name = "room_table")
        public class Room {
            @Id
            @Column(name = "room_id")
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            private int roomId;
            @Column(name = "room_name")
            private String roomName;
            @Column(name = "room_type")
            private String roomType;
            @OneToMany(mappedBy="roomList")
            private Collection<Device> deviceList = new ArrayList<>();
      
    
     //setters & getters
}

为了更新,我尝试了如下代码。

public class SaveDataClientTest {

    public static void main(String[] args) {
        try (Session session = HibernateUtil.getSessionFactory().openSession()) {
            session.beginTransaction();
         CriteriaBuilder userBuilder = session.getCriteriaBuilder();
            CriteriaUpdate<Device> deviceUpdate = userBuilder.createCriteriaUpdate(Device.class);
            Root<Device> deviceUpdateRoot = deviceUpdate.from(Device.class);

            Subquery<Device> deviceSubquery = deviceUpdate.subquery(Device.class);
            Root<Device> roomRoot = deviceSubquery.from(Device.class);
            Join<Device, Room> join = roomRoot.join("roomList", JoinType.LEFT);
            
             deviceUpdate.set(deviceUpdateRoot.get("dispalyName"), "DISPLAY12345"); 
            deviceUpdate.set(join.get("roomId"), 2);
        
            deviceUpdate.where(userBuilder.equal(deviceUpdateRoot.get("deviceName"), "DEVICE2"));
            int returnValue = session.createQuery(deviceUpdate).executeUpdate();
            System.out.println(returnValue);

            session.getTransaction().commit();
        } catch (HibernateException e) {
            e.printStackTrace();
        }
    }
}

我收到类似

的错误
Oct 01, 2020 8:00:03 PM org.hibernate.hql.internal.QueryTranslatorFactoryInitiator initiateService
INFO: HHH000397: Using ASTQueryTranslatorFactory
Oct 01, 2020 8:00:03 PM org.hibernate.hql.internal.ast.ErrorCounter reportError
ERROR:  Invalid path: 'generatedAlias1.roomId'
Oct 01, 2020 8:00:03 PM org.hibernate.hql.internal.ast.ErrorCounter reportError
ERROR:  Invalid path: 'generatedAlias1.roomId'
 Invalid path: 'generatedAlias1.roomId'
    at org.hibernate.hql.internal.ast.util.LiteralProcessor.lookupConstant(LiteralProcessor.java:111)
    at org.hibernate.hql.internal.ast.tree.DotNode.resolve(DotNode.java:214)
    at org.hibernate.hql.internal.ast.HqlSqlWalker.resolve(HqlSqlWalker.java:1038)
    at org.hibernate.hql.internal.ast.HqlSqlWalker.resolve(HqlSqlWalker.java:1026)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.assignment(HqlSqlBaseWalker.java:1054)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.setClause(HqlSqlBaseWalker.java:765)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.updateStatement(HqlSqlBaseWalker.java:381)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:269)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:266)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:189)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:141)
    at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:115)
    at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:77)
    at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:153)
    at org.hibernate.internal.AbstractSharedSessionContract.getQueryPlan(AbstractSharedSessionContract.java:553)
    at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:662)
    at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:3324)
    at org.hibernate.query.criteria.internal.AbstractManipulationCriteriaQuery.buildCompiledQuery(AbstractManipulationCriteriaQuery.java:112)
    at org.hibernate.query.criteria.internal.compile.CriteriaCompiler.compile(CriteriaCompiler.java:127)
    at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:3628)
    at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:203)
    at com.infotech.client.SaveDataClientTest.main(SaveDataClientTest.java:54)

Exception in thread "main" java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: Invalid path: 'generatedAlias1.roomId' [update com.infotech.entities.Device as generatedAlias0 set generatedAlias0.dispalyName = :param0, generatedAlias1.roomId = 2 where generatedAlias0.deviceName=:param1]
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:133)
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:157)
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:164)
    at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:670)
    at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:3324)
    at org.hibernate.query.criteria.internal.AbstractManipulationCriteriaQuery.buildCompiledQuery(AbstractManipulationCriteriaQuery.java:112)
    at org.hibernate.query.criteria.internal.compile.CriteriaCompiler.compile(CriteriaCompiler.java:127)
    at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:3628)
    at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:203)
    at com.infotech.client.SaveDataClientTest.main(SaveDataClientTest.java:54)
Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: Invalid path: 'generatedAlias1.roomId' [update com.infotech.entities.Device as generatedAlias0 set generatedAlias0.dispalyName = :param0, generatedAlias1.roomId = 2 where generatedAlias0.deviceName=:param1]
    at org.hibernate.hql.internal.ast.QuerySyntaxException.convert(QuerySyntaxException.java:74)
    at org.hibernate.hql.internal.ast.ErrorCounter.throwQueryException(ErrorCounter.java:91)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:272)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:189)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:141)
    at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:115)
    at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:77)
    at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:153)
    at org.hibernate.internal.AbstractSharedSessionContract.getQueryPlan(AbstractSharedSessionContract.java:553)
    at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:662)
    ... 6 more

你能帮我解决这个问题吗? 谢谢。

您尝试过以下方法吗?

        CriteriaUpdate<Device> deviceUpdate = userBuilder.createCriteriaUpdate(Device.class);
        Root<Device> deviceUpdateRoot = deviceUpdate.from(Device.class);
        
        deviceUpdate.set(deviceUpdateRoot.get("dispalyName"), "DISPLAY12345"); 
        deviceUpdate.set(deviceUpdateRoot.get("roomList").get("roomId"), 2);
    
        deviceUpdate.where(userBuilder.equal(deviceUpdateRoot.get("deviceName"), "DEVICE2"));
        int returnValue = session.createQuery(deviceUpdate).executeUpdate();

还是这个?

        CriteriaUpdate<Device> deviceUpdate = userBuilder.createCriteriaUpdate(Device.class);
        Root<Device> deviceUpdateRoot = deviceUpdate.from(Device.class);
        
        deviceUpdate.set(deviceUpdateRoot.get("dispalyName"), "DISPLAY12345"); 
        deviceUpdate.set(deviceUpdateRoot.get("roomList"), session.getReference(Room.class, 2));
    
        deviceUpdate.where(userBuilder.equal(deviceUpdateRoot.get("deviceName"), "DEVICE2"));
        int returnValue = session.createQuery(deviceUpdate).executeUpdate();