【问题标题】:Hibernate Persist Unidirectional One To Many RelationshipHibernate Persist 单向一对多关系
【发布时间】:2018-08-09 21:04:36
【问题描述】:

我有以下型号:

对应的映射如下:

引用实体

@Entity
@Table(name="Quote")
@Getter
@Setter
public class Quote {

    @Id
    @GeneratedValue(strategy= GenerationType.AUTO, generator="native")
    @GenericGenerator(name = "native", strategy = "native")
    @Column(name="idQuote")
    private int id;

    @Column(name="number")
    private String number;

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name="Quote_idQuote")
    private Set<Item> item;
}

物品实体

@Entity
@Table(name="Item")
@Getter
@Setter
public class Item {

    @Id
    @GeneratedValue(strategy= GenerationType.AUTO, generator="native")
    @GenericGenerator(name = "native", strategy = "native")
    @Column(name="idItem")
    private int id;

    @Column(name="name")
    private String name;

    @Column(name="Quote_idQuote")
    private int quoteId;
}

我遇到的问题是我无法保留带有项目列表的报价,这是我尝试执行此操作的代码:

SessionFactory sessionFactory;
Configuration configuration= new Configuration();
configuration.configure();
sessionFactory=configuration.buildSessionFactory();
Session session= sessionFactory.openSession();
session.beginTransaction();

Quote quote= new Quote();
quote.setNumber("ASR3E4E");

Set<Item> items= new HashSet<Item>();

Item item1= new Item();
item1.setName("Item 1");

Item item2= new Item();
item1.setName("Item 2");

items.add(item1);
items.add(item2);        

quote.setItem(items);

session.persist(quote);

session.getTransaction().commit();

我收到以下错误:

Hibernate: insert into Quote (number) values (?)
Hibernate: insert into Item (name, Quote_idQuote) values (?, ?)
Aug 09, 2018 3:27:25 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
WARN: SQL Error: 1452, SQLState: 23000
Aug 09, 2018 3:27:25 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
ERROR: Cannot add or update a child row: a foreign key constraint fails (`test`.`item`, CONSTRAINT `fk_Item_Quote` FOREIGN KEY (`Quote_idQuote`) REFERENCES `quote` (`idquote`))
Exception in thread "main" javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute statement
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:149)
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:157)
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:164)
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:831)

鉴于上述情况,这让我想到......如何自动休眠可以保持引用及其项目。为什么hibernate不首先生成Quote的id,持久化它,然后持久化一个Items? 我应该如何进行映射以保持单向关系并且我可以毫无问题地做我正在尝试的事情?

非常感谢!

【问题讨论】:

    标签: hibernate jpa hibernate-onetomany


    【解决方案1】:

    题中显示的数据库模型的正确映射方式如下:

    引用实体

    @Entity
    @Table(name="Quote")
    @Getter
    @Setter
    public class Quote {
    
        @Id
        @GeneratedValue(strategy= GenerationType.AUTO, generator="native")
        @GenericGenerator(name = "native", strategy = "native")
        @Column(name="idQuote")
        private int id;
    
        @Column(name="number")
        private String number;
    
        @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
        @JoinColumn(name = "Quote_idQuote", nullable=false)
        private Set<Item> item;
    }
    

    物品实体

    @Entity
    @Table(name="Item")
    @Getter
    @Setter
    public class Item {
    
        @Id
        @GeneratedValue(strategy= GenerationType.AUTO, generator="native")
        @GenericGenerator(name = "native", strategy = "native")
        @Column(name="idItem")
        private int id;
    
        @Column(name="name")
        private String name;
    
    }
    

    以及使用 Items 持久化 Quote 实体的代码:

    SessionFactory sessionFactory;
    Configuration configuration= new Configuration();
    configuration.configure();
    sessionFactory=configuration.buildSessionFactory();
    Session session= sessionFactory.openSession();
    session.beginTransaction();
    
    Quote quote= new Quote();
    quote.setNumber("ASR3E4E");
    
    Set<Item> items= new HashSet<Item>();
    
    Item item1= new Item();
    item1.setName("Item 1");
    
    Item item2= new Item();
    item2.setName("Item 2");
    
    items.add(item1);
    items.add(item2);        
    
    quote.setItem(items);
    
    session.persist(quote);
    
    session.getTransaction().commit();
    

    【讨论】:

      【解决方案2】:

      Hibernate 为灵活的代码提供双方映射。 如果您想从有价值的实体(项目)进行任何操作。 做正确的映射

      1) Quote.java 类

          @OneToMany(cascade = CascadeType.ALL, mappedBy="quote",fetch=FetchType.Eager)
      
      private Set<Item> item;
      

      2) Item.java 类内部

          @ManyToOne
          @JoinColumn(name="Quote_idQuote") 
          private Quote quote;  
      

      【讨论】:

        【解决方案3】:

        试试

           item1.setQuote(quote);
           item2.setQuote(quote);
           session.persist(quote);
        

        在您的情况下,由于您无法在此处设置关系,因此不可能成功:如果:

        移除级联 = CascadeType.ALL,

        session.persist(quote); // this must be done first to actually get bloody quote ID that you can propagate
        item1.setQuoteId(quote.getId()); //or something to set quoteid
        item2.setQuoteId(quote.getId())=quote.id; //or something to set quoteid
        session.persist(item1);
        session.persist(item2);
        

        【讨论】:

        • 非常感谢您的回答,但我希望收到有关它的解释,例如,为什么 item1.setQuote(quote) if the item don't have a Quote
        • item 是外键的持有者(包含引用的PK),所以你必须在item 上设置关系。现在你正在做其他事情。由于您没有这样做,hibernate 会生成不包含指向引号的指针的插入 SQL - 因此违反约束。
        • 我只是懒得纠正你的模型,所以让我们等待其他人为你做这件事。您可以从private Quote quote;开始自己尝试
        • @Antoniosss 好的,为什么?
        • 因为普通模型会有 Item->private Quote 报价;这就是对象关系映射背后的全部目的和理念
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-02-16
        • 1970-01-01
        • 2015-02-05
        • 2013-12-28
        • 1970-01-01
        • 1970-01-01
        • 2018-10-28
        相关资源
        最近更新 更多