键'PRIMARY'的重复条目'string1-string2' [英] Duplicate entry 'string1-string2' for key 'PRIMARY'

查看:639
本文介绍了键'PRIMARY'的重复条目'string1-string2'的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在使用hibernate和jpa在MySQL数据库上的Spring MVC应用程序中,每当我尝试保存包含子实体的父实体时,我都会收到有关子实体的以下错误消息:

 键'PRIMARY'的重复条目'string1-string2'

这里, string1 string2 指的是组合主键的两部分子实体。 我该如何解决这个错误?



这是实体之间的关系在父节点地址实体:

  @ManyToOne(cascade = {CascadeType.ALL},fetch = FetchType.EAGER )
@JoinColumns({@JoinColumn(name =usecode,referencedColumnName =code,insertable = false,updatable = false),
@JoinColumn(name =usecodesystem,referencedColumnName =codesystem ,insertable = false,updatable = false)
})
public HL7GeneralCode use;

以下是在子元素 GeneralCode
$ p $ @OneToMany(mappedBy =use,cascade = {CascadeType.ALL})
私人设置< HL7地址>地址;

可以查看完整的堆栈跟踪点击此链接

地址实体的完整代码可以在此链接中找到 $ b

可以读取 GeneralCode 实体的完整代码在此链接

复合主键类的代码可以在 at此链接

Address 扩展的 BaseEntity 类可以此链接



我有阅读有关此错误消息的许多帖子。其他帖子的答案不能解决我的错误消息,并且他们通常不会解决我的实体使用组合主键这一事实。




编辑:

坚持地址的代码是:

  @Override 
public void savehl7Address(HL7Address addr){
如果((Integer)addr.getId()== null){
System.out.println([[[[[[] []]]]]]]] ]]]]]]]]]]]]);
this.em.persist(addr);}
else {
System.out.println(]]]]]]]]]]]]]]]]]有关合并地址[[[[[[[[[[[[[[[[[
this.em.merge(addr);}
}






第二次编辑:



我试图按照@Ben75的建议,但代码崩溃在这行.em.persist(addr.getUse()); 。请注意,他的if子句不适合我的实际对象模型,所以我将if子句更改为 if(addr.getUse()!= null&& addr.getId()== null) 。这是我的代码。

  @Override 
public void savehl7Address(HL7Address addr){
if(addr .getUse()!= null&& addr.getId()== null){
//此下一行在应用程序崩溃之前打印在堆栈跟踪中
System.out.println( about to this.em.persist(addr.getUse()););
// HL7GeneralCode不是持久化的
this.em.persist(addr.getUse());
//因为在地址关系addr上有一个cascade ALL现在持久化
return;
}
System.out.println(=========================== inside jpahl7patientrespository.savehl7Address(addr) );如果((整数)addr.getId()== null){
System.out.println([[[[[[[关于持久地址]]]] ]]]]]]]]]]]]]]]]);
this.em.persist(addr);}
else {
System.out.println(]]]]]]]]]]]]]]]]]有关合并地址[[[[[[[[[[[[[[[[[
this.em.merge(addr);}
}

相关现在是HL7Address的一部分:

  @ManyToOne(fetch = FetchType.EAGER)
@JoinColumns({@JoinColumn( name =usecode,referencedColumnName =code,insertable = false,updatable = false),
@JoinColumn(name =usecodesystem,referencedColumnName =codesystem,insertable = false,updatable = false)
})
public HL7GeneralCode use;

现在HL7GeneralCode的相关部分是:

  @OneToMany(mappedBy =use)
private Set< HL7Address>地址;

新的堆栈跟踪可以读取点击此链接



如何解决此错误?






THIRD EDIT:



通过将下面的代码添加到保存地址方法中:

  if(addr.getUse()!= null&&! this.em.contains(addr.getUse())){
System.out.println(about to this.em.persist(addr.getUse()););
this.em.persist(addr.getUse()); return;

$ / code>

不幸的是,我仍然得到相同的错误,尽管堆栈跟踪 SYSO 表示上述代码刚好在应用程序崩溃之前运行。

您可以阅读生成的堆栈跟踪点击此链接

解决方案

首先有一些事情要清除:


  1. HL7GeneralCode(父级)和HL7Address(子级)之间有双向关联。如果HL7GeneralCode.addresses是反面(mappedBy),那么为什么拥有方HL7Address.use具有可插入/可更新错误?拥有方应该控制这个关联,所以你应该删除insertable / updatable = false标志。


  2. 从Parent级联到Child级别总是有意义的,而不是相反。但是在你的用例中,你试图坚持孩子并自动坚持父母。这就是为什么在多对一端的CASCADE.ALL没有任何意义。

  3. 当使用双向关联时,双方都必须设置: / p>

      HL7Address addr = new HL7Address(); 
    HL7GeneralCode code = new HL7GeneralCode();
    ...
    code.getAddresses()。add(addr);
    addr.setUse(code);


  4. 持久化操作是为了插入瞬态实体,决不会合并它们或重新连接实体。这意味着当您调用服务方法时,HL7Address和HL7GeneralCode都是新实体。如果您已经保存了一个具有相同ID的HL7GeneralCode,您将得到主键违反例外。

  5. 如果HL7GeneralCode可能存在,那么你应该从数据库获取它。

      HL7GeneralCode code = em.find(HL7GeneralCode,pk); 
    HL7Address addr = new HL7Address();
    if(code!= null){
    code = new HL7GeneralCode();
    em.persist(code);
    }
    code.getAddresses()。add(addr);
    addr.setUse(code);
    em.persist(addr);


更新


  1. HL7Address地址不会覆盖equals / hashCode,因此默认对象的引用检查规则适用。这将确保我们可以从code.addresses列表中添加/删除地址。如果您稍后改变主意,请确保正确实施equals和hashCode

  2. 虽然与您的问题无关,但您可能希望使用getter / setter而不是公开您的字段。这提供了更好的封装,您将避免混合setter与公共字段访问。




  3. savehl7Address方法:

      @Override 
    public void savehl7Address(HL7Address addr){
    HL7GeneralCode code = addr.use();
    if(code!= null&& code.getId()== null){
    // HL7GeneralCode不是持久的。我们不支持
    抛出新的IllegalStateException(不能使用非持久HL7GeneralCode持久化地址);
    //如果你想支持它
    // code = em.find(HL7GeneralCode,code.getId());
    }
    //合并没有任何地址信息的代码
    //这将确保我们只重新附加代码而不触发地址
    //通过可达性传递持久性
    addr.setUse(NULL);
    code.getAddresses()。remove(addr);
    code = em.merge(code);

    //现在将代码设置为地址,反之亦然
    addr.setUse(code);
    code.getAddresses()。add(addr); ((Integer)addr.getId()== null){
    System.out.println([[[[[[[] [关于持久化地址]]]]]]]]]]]]]]]]]]]]);
    em.persist(addr);

    else {
    System.out.println(]]]]]]]]]]]]]]]]]]合并地址[[[[[[[ [[[[[[[[[[[[[[[);
    addr = em.merge(addr);
    }
    }


    In a Spring MVC application using hibernate and jpa over a MySQL database, I am getting the following error message about a child entity whenever I try to save a parent entity that includes the child entity:

    Duplicate entry 'string1-string2' for key 'PRIMARY'  
    

    Here, string1 and string2 refer to the two parts of the composite primary key of the child entity. How do I resolve this error?

    Here is the way that the relationship between the entities is defined in the parent Address entity:

    @ManyToOne(cascade = { CascadeType.ALL }, fetch=FetchType.EAGER)
    @JoinColumns({ @JoinColumn(name = "usecode", referencedColumnName = "code", insertable = false, updatable = false),
            @JoinColumn(name = "usecodesystem", referencedColumnName = "codesystem", insertable = false, updatable = false)
    })
    public HL7GeneralCode use;
    

    Here is the way the relationship is defined in the child GeneralCode entity:

    @OneToMany(mappedBy = "use", cascade = {CascadeType.ALL})
    private Set<HL7Address> addresses;
    

    The complete stack trace can be viewed by clicking on this link.
    The complete code for the Address entity can be found at this link.

    The complete code for the GeneralCode entity can be read at this link.

    The code for the composite primary key class can be found at this link.
    And the BaseEntity class that is extended by Address can be found at this link.

    I have read many postings on this error message. The answers to the other postings do not resolve my error message, and they generally do not address the fact that my entity uses a composite primary key.


    EDIT:

    The code for persisting the address is:

    @Override
    public void savehl7Address(HL7Address addr) {
        if ((Integer)addr.getId() == null) {
            System.out.println("[[[[[[[[[[[[ about to persist address ]]]]]]]]]]]]]]]]]]]]");
            this.em.persist(addr);}
        else {
            System.out.println("]]]]]]]]]]]]]]]]]] about to merge address [[[[[[[[[[[[[[[[[[[[[");
            this.em.merge(addr);}
    }
    


    SECOND EDIT:

    I tried to follow @Ben75's advice, but the code is crashing at the line this.em.persist(addr.getUse());. Note that his if clause did not fit my actual object model, so I changed the if clause below to if(addr.getUse() != null && addr.getId()==null). Here is my code.

    @Override
    public void savehl7Address(HL7Address addr) {
        if(addr.getUse() != null && addr.getId()==null){
            //this next line prints in the stack trace right before the app crashes
            System.out.println("about to this.em.persist(addr.getUse());");
            //HL7GeneralCode is not persistent yet
            this.em.persist(addr.getUse());
            //since there is a cascade ALL on the adresses relationship addr is now persistent
            return;
        }
        System.out.println("=========================== inside jpahl7patientrespository.savehl7Address(addr)");
        if ((Integer)addr.getId() == null) {
            System.out.println("[[[[[[[[[[[[ about to persist address ]]]]]]]]]]]]]]]]]]]]");
            this.em.persist(addr);}
        else {
            System.out.println("]]]]]]]]]]]]]]]]]] about to merge address [[[[[[[[[[[[[[[[[[[[[");
            this.em.merge(addr);}
    }
    

    The relevant part of HL7Address is now:

    @ManyToOne(fetch=FetchType.EAGER)
    @JoinColumns({ @JoinColumn(name = "usecode", referencedColumnName = "code", insertable = false, updatable = false),
            @JoinColumn(name = "usecodesystem", referencedColumnName = "codesystem", insertable = false, updatable = false)
    })
    public HL7GeneralCode use;
    

    The relevant part of HL7GeneralCode is now:

    @OneToMany(mappedBy = "use")
    private Set<HL7Address> addresses;
    

    The new stack trace can be read by clicking on this link.

    How can I resolve this error?


    THIRD EDIT:

    I followed ben75's advice by adding the following code to the save address method:

    if(addr.getUse() != null && !this.em.contains(addr.getUse())){
        System.out.println("about to this.em.persist(addr.getUse());");
        this.em.persist(addr.getUse());return;
    }
    

    Unfortunately, I am still getting the same error despite the fact that the stack trace SYSO indicates that the above code is running just before the app crashes.

    You can read the resulting stack trace by clicking on this link.

    解决方案

    First of all there are some things to clear out:

    1. You have a bidirectional association between HL7GeneralCode(the parent) and HL7Address (the child). If the HL7GeneralCode.addresses is the "inverse" side (mappedBy) then why the owning side HL7Address.use has insertable/updatable false? The owning side should control this association so you should remove the insertable/updatable=false flags.

    2. It always makes sense to cascade from the Parent to the Child, not the other way around. But in your use case, you try to persist the Child and automatically persist the Parent too. That's why the CASCADE.ALL on the many to one end doesn't make sense.

    3. When using bidirectional associations, both sides are mandatory to be set:

      HL7Address addr = new HL7Address();
      HL7GeneralCode code = new HL7GeneralCode();
      ...
      code.getAddresses().add(addr);
      addr.setUse(code); 
      

    4. The persist operation is meant to INSERT transient entities, never to merge them or reattach entities. This implies that both the HL7Address and the HL7GeneralCode are new entities when you call your service method. If you have already saved a HL7GeneralCode with the same ID, you will get the primary key constraint violation exception.

    5. If the HL7GeneralCode is possible to exist, then you should fetch it from db.

      HL7GeneralCode code = em.find(HL7GeneralCode, pk);
      HL7Address addr = new HL7Address();
      if(code != null) {
         code = new HL7GeneralCode();
         em.persist(code);    
      }
      code.getAddresses().add(addr);
      addr.setUse(code);            
      em.persist(addr);
      

    UPDATE

    1. The HL7Address address doesn't override equals/hashCode so the default object same reference check rule applies. This will ensure we can add/remove addresses from the code.addresses List. In case you change your mind later, make sure you implement equals and hashCode properly.

    2. Although not related to your issue, you might want to use getter/setter instead of making your fields public. This provides better encapsulation and you will avoid mixing setters with public field access.

    The savehl7Address method:

    @Override
    public void savehl7Address(HL7Address addr) {
        HL7GeneralCode code = addr.use();
        if(code != null && code.getId()==null){
        //HL7GeneralCode is not persistent. We don't support that
            throw new IllegalStateException("Cannot persist an adress using a non persistent HL7GeneralCode");
           //In case you'd want to support it
           //code = em.find(HL7GeneralCode, code.getId());
        }
        //Merge the code without any address info        
        //This will ensure we only reattach the code without triggering the address 
        //transitive persistence by reachability
        addr.setUse(null);
        code.getAddresses().remove(addr);
        code = em.merge(code); 
    
        //Now set the code to the address and vice-versa  
        addr.setUse(code);
        code.getAddresses().add(addr);
    
        if ((Integer)addr.getId() == null) {
            System.out.println("[[[[[[[[[[[[ about to persist address ]]]]]]]]]]]]]]]]]]]]");
            em.persist(addr);
        }
        else {
            System.out.println("]]]]]]]]]]]]]]]]]] about to merge address [[[[[[[[[[[[[[[[[[[[[");
            addr = em.merge(addr);
        }       
    }
    

    这篇关于键'PRIMARY'的重复条目'string1-string2'的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆