gpt4 book ai didi

java - Hibernate 与同一类的多个多对多关系

转载 作者:行者123 更新时间:2023-12-02 04:33:23 25 4
gpt4 key购买 nike

我在 hibernate 和映射相同类型的多个对象时遇到问题,也许我只是愚蠢。

我有一个产品

@Entity
@Table(name = "product")
public class Product {

@Id
private int id;

@ManyToMany(cascade = CascadeType.ALL)
private List<LanguageBasedText> name;

@ManyToMany(cascade = CascadeType.ALL)
private List<LanguageBasedText> longDesc;

(...)
}

和基于语言的文本

@Entity
@Table(name = "languageBasedText")
public class LanguageBasedText {

@EmbeddedId
private LanguageTextEmbeddedKey embeddedID;

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

}

带有嵌入式 key

@Embeddable
public class LanguageTextEmbeddedKey implements Serializable {

@Column(name = "productID")
private int productID;
@Column(name = "lang")
private String lang;
@Column(name = "type")
private String type;
//i get the type from an other source and it is the information where
//the text goes (name or longDesc or 100 other posibil multi
//language text fields)
}

问题是:我如何让 hibernate 正确映射

我想要一张像这样的 table

文本

产品 ID |郎 |类型 |文本

产品

产品 ID |其他一些东西|

最佳答案

摘要:您实际上并不需要多对多,您需要在多方进行一对多继承(使用每个层次结构单表策略),或者对 OneToMany 属性进行过滤使用@Where 。前一种方法可能是“更多的 OO”,后者可以减少输入,并且如果您有许多不同的 i18n 文本字段,则可能会防止类爆炸。两者@DiscriminatorOptions@Where是 hibernate 注释,因此无论哪种方式您都偏离了标准 JPA 注释。

模型

如果您考虑 ManyToMany方法你可以看到没有过滤器来指定 type='name'标准,name可以拉回longDesc文本以及 name相同语言的文本 - 这是不对的。因此,如果您应用过滤器,那么您现在有 OneToMany因为你只有一个 name{productID, lang} .

如果您从纯粹的建模角度考虑这一点:

  • 一个Product可以有很多Name s,但每个 lang 只有一个名称;
  • 所以每个Name候选键 {ProductId, Lang} 是唯一的;
  • LongDesc 也是如此;
  • 因此您可以查看 NameLongDesc作为独立的商业实体。

因此这是 OneToMany每个 LanguageBasedText 的模型属性 ProductName , LongDesc (以及您提到的其他类似属性)恰好共享相同的属性:它们实现相同的接口(interface),因此可以将它们存储在带有鉴别器的一个表中。

继承策略

您可以利用文本实体的通用接口(interface)并实现继承策略。在您的例子中,有了鉴别器列,您就跳到了前面,自然地使用了单表每层次继承模型。在您的代码中,您实际上拥有:

public abstract class LanguageBasedText {}
public class NameText extends LanguageBasedText {}
public class LongDescText extends LanguageBasedText {}
public class Product {
private Set<NameText> names;
private Set<LongDescText> longDescs;
}

代码

用 JPA 表达它并使其与 Hibernate 一起工作:

  1. 创建根实体类型,通常为 abstract@Entity以防止直接存储。指定@Table为了清楚起见,连同 @DiscriminatorFormula .
  2. 另添加@org.hibernate.annotations.DiscriminatorOptions(force=true) - 这解决了将错误类型加载到 Product 中的 i18n 属性中的问题
  3. 继承 @Entity类如 NameText extends LanguageBasedText
  4. 添加 @OneToMany属性到 Product 中,键入为文本类子类型参数化的集合(例如 Set<NameText> )。

在代码中:

@Entity @Table(name = "product")
public class Product {
@Id @GeneratedValue(strategy = GenerationType.AUTO)
Integer id;

private Product() {}
public Product(String sku) {
this.sku = sku;
}

// omitting the other properties
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "productID", insertable = false, updatable = false)
private Set<NameText> name = new HashSet<>();

@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "productID", insertable = false, updatable = false)
private Set<LongDescText> longDesc = new HashSet<>();

private String sku;
...
}

@Embeddable public class LanguageTextEmbeddedKey implements Serializable {
private LanguageTextEmbeddedKey(){}
public LanguageTextEmbeddedKey(int productID, String lang, String type) {
this.productID = productID;
this.lang = lang;
this.type = type;
}

@Column(name = "productID") private int productID;
@Column(name = "lang") private String lang;
@Column(name = "type") private String type;
...
}

@Entity @Table(name = "languageBasedText")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorFormula(value="type")
@org.hibernate.annotations.DiscriminatorOptions(force=true)
public abstract class LanguageBasedText {
@EmbeddedId private LanguageTextEmbeddedKey embeddedID;
@ManyToOne() @JoinColumn(name="productID", insertable=false,updatable=false, nullable=false)
protected Product p;
private String text;

protected LanguageBasedText(){}
protected LanguageBasedText(int productID, String lang, String type, String text) {
this.embeddedID = new LanguageTextEmbeddedKey(productID, lang, type);
this.text = text;
}
...
}

@Entity @DiscriminatorValue("name")
public class NameText extends LanguageBasedText {
private NameText(){}
public NameText(int productID, String lang, String text) {
super(productID, lang, "name", text);
}
}
// similarly for LongDescText

注意上面还缺少很多其他(不太相关)的代码,包括所有类型上强制的无参数构造函数、修改器/访问器等。我还使用过 productID在文本类的构造函数中,但我建议您将这些构造函数替换为 DDD 方法,例如 addNameText封装该 id。

关于java - Hibernate 与同一类的多个多对多关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31156550/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com