在数据库上插入实体+外键的正确方法(使用:Mysql,JPA)

Posted

技术标签:

【中文标题】在数据库上插入实体+外键的正确方法(使用:Mysql,JPA)【英文标题】:Right way to make insertion of an entity + foreign key on database(Use : Mysql, JPA) 【发布时间】:2017-09-17 01:41:00 【问题描述】:

我有一个关于在数据库(mysql、JPA)上插入我的实体+外键的正确方法的问题。 在问我的问题之前,我尝试了我找到的解决方案,我花了几天时间自己解决问题。 我相信我有问题:

我需要做的是:

    我已经在站点表中存在数据(信息) 我必须在序列表中插入新序列 我必须在序列表中插入新序列,并关联FK站点(站点存在,无需再次插入)

主要问题是:

    当我在序列表中插入时,我得到了带有 FK 位点的序列 正确插入 但是!问题是我也有站点插入 在数据库中,所以每次插入时都会冗余插入站点 序列数据
我只需要插入一个带有关联的序列(站点的 FK)。 下面是我的控制台上发生的事情: 休眠:插入站点(Current_Sequence、Date_Insert、Date_Update、Enable、Nom_Site、User_Update、applicationService_Id_SA、partner_Id_Partner、Id_Site)值(?、?、?、?、?、?、?、?、?) Hibernate:插入序列(Date_Insert_timestamp、Date_Update_timestamp、Nbr_PDF、Nbr_ZPL、Size_PDF、Size_ZPL、TimestampMinute、User_Update、site_Id_Site、status、Id_Sequence)值(?、?、?、?、?、?、?、?、?、?、 ?) Hibernate:插入 Sites_Sequences (Site_Id_Site,sequence_Id_Sequence) 值 (?, ?)

Jpa 存储库:我首先按名称获取 Site 对象

@覆盖 公共站点 findSiteByName(String Name_Site) 列出站点 = entityManager.createQuery("SELECT s FROM Site s").getResultList(); 对于(网站项目:网站) if (item.getNom_Site().equals(Name_Site)) 归还物品; 返回空值; Jpa方法在数据库中插入序列
@Override
    public Sequence saveSequence(Sequence sequence) 

        return super.save(sequence);
    
我的休息控制器:
@GET
@Path("/addSeq")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Sequence addSeq(@Context final UriInfo uriInfo) 
    Site site = siteService.findSiteByName("Name_Site");
    Sequence sequence = sequenceFactory.CreateSequence(new Date(), new Date(), "", "", "", 4, 6, 10, 12);
    sequence.setSite(site);
    site.getSequences().add(sequence);
    sequenceservice.saveSequence(sequence);
    return null;

我的主要课程是:
@Entity
@Table(name = "Sequences")
public class Sequence 
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "Id_Sequence", unique = true, nullable = false)
private long Id_Sequence;
private Date ....;
private Date ....;
private String ....;
private String ....;
private String ....;
private int ....;
private int ....;
private double ....;
private double ....;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<TraceSequence> traceSequences = new HashSet<>();
@ManyToOne(cascade = CascadeType.ALL)
private Site site;

public constructor...

public set..
public get..

@实体 @Table(name = "网站") 公共类站点

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "Id_Site", unique = true, nullable = false)
private long Id_Site;
private String ...;
private boolean ...;
private long ...; 
private Date ...;
private Date ...;
private String ...;

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<Sequence> sequences = new HashSet<>();

@ManyToOne
private ... ...;

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<...> ... = new HashSet<>();

@ManyToOne
private ... ...;

public constructor...

public set..
public get..

【问题讨论】:

super.save(sequence)后面叫什么? 您能否检查一下Site site = siteService.findSiteByName("Name_Site"); 是否提供了具有正确Id_Site 值的站点? 在 super.save(sequence) 后面 ==> JpaSequenceRespository 扩展 BaseJpaRepository Site site = siteService.findSiteByName("Name_Site") ==> 是的,我检查了它返回的内容,我得到了 Site 的完整对象 你有自己的BaseJpaRepository 还是来自哪里? 【参考方案1】:

您可以尝试删除所有关系中的cascade = CascadeType.ALL 吗?我认为主要问题是CascadeType.PERSIST 级联到子元素。你可以看看这里JPA with JTA: Persist entity and merge cascaded child entities

我建议的另一件事是将表数从 3 减少到 2。由于您使用的是 OneToMany-relation,它不需要像现在这样的映射表。为了实现这一点,在 OneToMany 注释中使用了 mappedBy 子句,并在 ManyToOne 站点上使用了附加的 JoinColumn 注释。

@Entity
@Table(name = "Sites")
public class Site 

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "Id_Site", unique = true, nullable = false)
    private long Id_Site;
    private String ...;
    private boolean ...;
    private long ...; 
    private Date ...;
    private Date ...;
    private String ...;

    @OneToMany(mappedBy="site", fetch = FetchType.EAGER)
    private Set<Sequence> sequences = new HashSet<>();


@Entity
@Table(name = "Sequences")
public class Sequence 

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "Id_Sequence", unique = true, nullable = false)
    private long Id_Sequence;
    private Date ....;
    private Date ....;
    private String ....;
    private String ....;
    private String ....;
    private int ....;
    private int ....;
    private double ....;
    private double ....;

    @OneToMany(fetch = FetchType.EAGER)
    private Set<Sequence> traceSequences = new HashSet<>();

    @ManyToOne(cascade = CascadeType.MERGE)
    @JoinColumn(name = "site_Id_Site", nullable = false)
    private Site site;

已编辑 我试过了:

public interface SequenceRepository extends JpaRepository<Sequence, Long> 


Site site = siteRepository.findOne(1L);

Sequence seq = new Sequence();
seq.setSite(site);
site.getSequences().add(seq);

sequenceRepository.save(seq);

带来

Hibernate: select site0_.id_site...
Hibernate: insert into sequences (site_id_site) values (?)

在类路径中我确实有spring-data-rest-webmvc-2.5.6.RELEASE.jar

【讨论】:

感谢您的回答, 我昨天更改了代码以使用 CascadeType.MERGE,它只会更新您的网站。 CascadeType.MERGE ==> 给了我同样的错误:org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - 在查询刷新之前保存瞬态实例:com.xxx.xxx.xxx.model。 sequence.Sequence.site -> com.xxx.xxx.xxx.model.site.Site CascadeType.PERSIST ==> 插入站点和序列 我想我找到了问题的根源。我在 Site 表上手动插入了一行,PK 为“0”,当我得到“Site site = siteService.findSiteByName("Name_Site")”==> 我也得到 PR 为“0”(空) ,据我了解,当 PR 等于“0”时,休眠就像插入新实体一样。

以上是关于在数据库上插入实体+外键的正确方法(使用:Mysql,JPA)的主要内容,如果未能解决你的问题,请参考以下文章

ssh关于含有外键的传值中无法识别正确的action的原因和解决办法

实体框架中与代码优先外键的更改冲突

为什么在Django上使用bulk_create插入带有外键的数据会返回“属性对象不可调用”?

如何在DJANGO里,向有外键的DB里插入数据

知识盲点:存在外键的的表,在插入数据时应该如何操作?

Mysql外键和表关系