为什么 Hibernate 会生成不必要的约束?

huangapple go评论73阅读模式
英文:

Why hibernate generates unnecessary constraint?

问题

以下是翻译好的内容:

我在使用Hibernate中的双向关系生成的SQL方面遇到了一个奇怪的问题。以下是代码示例。

首先是@OneToMany关系:

@Entity
@Table(name = "employers")
public class Employer {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "eid")
    private Long employerId;
    
    private String name;
    
    @OneToMany(mappedBy = "titleId")
    private Set<Title> titles = new TreeSet<>(); 
    
    // 获取器/设置器...
}

然后是@ManyToOne关系:

@Entity
@Table(name = "titles")
public class Title {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "tid")
    private long titleId;
    
    /**
     * 不确定是否需要在这里建立双向关系。
     */
    @ManyToOne
    @JoinColumn(name = "employerId")
    private Employer employer;

    // 获取器/设置器...
}

我对Spring Boot和Hibernate相对较新,所以这是我尝试运行的第一件事情。根据我参考的教程和文档,在我的情况下生成的SQL是错误的。

以下是生成的SQL(Postgres9Dialect

CREATE TABLE public.items
(
    item_id bigint NOT NULL DEFAULT nextval('items_item_id_seq'::regclass),
    text character varying(255) COLLATE pg_catalog."default",
    title_tid bigint,
    CONSTRAINT items_pkey PRIMARY KEY (item_id),
    CONSTRAINT fkkwhqrl3vscoqcacws6kgsdlx5 FOREIGN KEY (item_id)
        REFERENCES public.titles (tid) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION,
    CONSTRAINT fkluhgxmnakeuroph186b2k05eq FOREIGN KEY (title_tid)
        REFERENCES public.titles (tid) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION
)

问题出在这个约束上:

CONSTRAINT fkkwhqrl3vscoqcacws6kgsdlx5 FOREIGN KEY (item_id)
REFERENCES public.titles (tid) MATCH SIMPLE
   ON UPDATE NO ACTION
   ON DELETE NO ACTION,

这会导致如果标题ID(tid)超过雇主ID(雇主表中的eid)的最高编号,将不允许创建其他标题。生成的雇主表是正确的。

如果我手动删除这个约束,那么它就会按预期工作。

为什么会创建这个错误的约束?我漏掉了什么?

(另外,这里的"title"是指一个人在特定雇主那里拥有的头衔,而不是书的标题,因此我不是在尝试结合雇主和作者教程)

英文:

I'm having a strange problem with the SQL generated by a bidirectional relationship in Hibernate. Here's the code.

First the @OneToMany side:

@Entity
@Table(name = &quot;employers&quot;)
public class Employer {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = &quot;eid&quot;)
	private Long employerId;
	
	private String name;
	
	@OneToMany(mappedBy = &quot;titleId&quot;)
	private Set&lt;Title&gt; titles = new TreeSet&lt;&gt;(); 
    
    // Getters/setters...
}

And the @ManyToOne side:

@Entity
@Table(name = &quot;titles&quot;)
public class Title {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = &quot;tid&quot;)
	private long titleId;
	
	/**
	 * Not sure if I need a bi-directional relation here.
	 */
	@ManyToOne
	@JoinColumn(name = &quot;employerId&quot;)
	private Employer employer;

    // Getters/setters...
}

I'm fairly new to springboot and hibernate, so this is the first thing I've attempted that would actually run. Based on the tutorials and the documentation I've referenced, the SQL generated in my case is wrong.

Here's the generated SQL (Postgres9Dialect)

CREATE TABLE public.items
(
    item_id bigint NOT NULL DEFAULT nextval(&#39;items_item_id_seq&#39;::regclass),
    text character varying(255) COLLATE pg_catalog.&quot;default&quot;,
    title_tid bigint,
    CONSTRAINT items_pkey PRIMARY KEY (item_id),
    CONSTRAINT fkkwhqrl3vscoqcacws6kgsdlx5 FOREIGN KEY (item_id)
        REFERENCES public.titles (tid) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION,
    CONSTRAINT fkluhgxmnakeuroph186b2k05eq FOREIGN KEY (title_tid)
        REFERENCES public.titles (tid) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION
)

The problem is this constraint:

CONSTRAINT fkkwhqrl3vscoqcacws6kgsdlx5 FOREIGN KEY (item_id)
REFERENCES public.titles (tid) MATCH SIMPLE
   ON UPDATE NO ACTION
   ON DELETE NO ACTION,

It has the effect of not allowing additional titles from being created if the title id (tid) exceeds the highest number of employer ids (eid in the employer table). The generated employers table is correct.

If I delete this constraint manually, then it works as expected.

Why is it creating this erroneous constraint? What am I missing?

(as an aside, title refers to a title one would have for a particular employer, not a book title, so I am not trying to combine employer & author tutorials)

答案1

得分: 5

你应该以以下方式更正你的映射:

@Entity
@Table(name = "employers")
public class Employer {
    @OneToMany(mappedBy = "employer")
    private Set<Title> titles = new TreeSet<>(); 
    // ...
}

@Entity
@Table(name = "titles")
public class Title {

    @ManyToOne
    @JoinColumn(name = "employerId")
    private Employer employer;
    // ...
}

mappedBy 应该保存关联的另一侧的字段名。

英文:

You should correct your mapping in this way:

@Entity
@Table(name = &quot;employers&quot;)
public class Employer {
    @OneToMany(mappedBy = &quot;employer&quot;)
    private Set&lt;Title&gt; titles = new TreeSet&lt;&gt;(); 
    // ...
}

@Entity
@Table(name = &quot;titles&quot;)
public class Title {

    @ManyToOne
    @JoinColumn(name = &quot;employerId&quot;)
    private Employer employer;
    // ...
}

The mappedBy should hold the field name of another side of association.

huangapple
  • 本文由 发表于 2020年9月6日 21:08:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/63764507.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定