我如何结合 TABLE_PER_CLASS 和 GenerationType.IDENTITY
How can I combine TABLE_PER_CLASS and GenerationType.IDENTITY
亲爱的未来reader:在完成和他提供的link之后,我决定改用序列。较新的 Hibernates 注意它也适用于 MySQL。
我有一个 abstract
class,其中包含我希望在我的所有实体中拥有的一些基本值(例如 ID、创建日期、创建用户等)。目前,我正在为每个具体 class 具有 table 并使其 id 工作的组合而苦苦挣扎。
看来我可以有一个 table 每个 class 或一个我配置 ID 的地方,但不能同时有两个。这对我来说似乎很奇怪而且不太可能,所以我想确保情况确实如此。
可能相关的版本:hibernate 5、mysql 5.5、java 1.8、spring 4.3。
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@MappedSuperclass
public abstract class GeneralData implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(nullable = false)
protected int id;
protected String name;
// getters, setters, constructors, etc.
}
示例子class:
@Entity
public class ExampleClass extends GeneralData {
// own values, constructors, getters, setters, etc.
}
我得到的错误:
Cannot use identity column key generation with <union-subclass> mapping for: org.example.ExampleClass
我尝试过的事情:
- 我曾尝试将
GeneralData
变成 @Entity
,但这没有帮助。
- I tried to 使用
GenerationType.TABLE
但由于密钥太大而失败。 (另外,我宁愿不要这个,IDENTITY 是我想要的)错误:Specified key was too long; max key length is 1000 bytes
我不想将 id 列移动到每个具体 class。如果 ID 仅对单个 table 而不是整个依赖树唯一,我完全没问题。
如果我应该升级我的库、数据库等,请记住,这只能通过大量额外的工作来完成(出于内部原因)。这将是最后的手段,我希望首先看到一些它有帮助的证据。
对同一父实体的所有子对象的要求是它们之间具有唯一的 ID。
例如,假设您有一个父实体 GeneralData
,然后使用 id=1 存储子类型 A
。
这将是完全合法的:
GeneralData loaded = entitymanager.find( GeneralData.class, 1 );
当然 loaded
的类型将是 A
:子类。 映射必须确保没有歧义:不允许其他子类也使用“1”作为 ID,即使它映射到不同的 table。
在你的例子中,你要求 Hibernate 将 GeneralData
的每个不同子类型存储到它自己单独的 Table.
您还要求 MySQL - 它不知道这些 table 以任何方式相关 - 自动分配唯一标识符。
无法指示 MySQL 这些 table 中的每一个都需要使用相同的 Identity
"sequence",因为它们不是真正的序列:因此此映射是非法的!这会给您带来麻烦,因为它会将重叠 ID 分配给父实体的不同子类型,这违反了上述语义。
这是使用 IDENTITY 的局限性的一个很好的例子;此外,IDENTITY 不是很有效,因为它意味着 Hibernate 需要在实体持久化后立即写入实体,而不是能够更有效地将刷新操作推迟到更合适的时间,因此可能会批量写入或完全跳过它们(特别是如果事务被中止,而且如果您在持久化之后更新实体但仍在同一事务中)。
我建议看看不同的 Identifier generator strategies for such hierarchies, and in particular Optimizers 可能会大大提高您的应用程序的性能。
每个具体 class 映射可以有 2 个不同的 table :
- 对于隐式多态性,无法使用多态查询,但您可以使用 IDENTITY 策略(正如 Sanne 指出的那样效率不高)。标识符可以在 superclass 或 subclasses.
中定义
- with union, 不允许 IDENTITY 策略(Sanne 已经清楚地解释了原因)。标识符必须在 superclass
中定义
第一个映射是
@MappedSuperclass
public abstract class GeneralData implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(nullable = false)
protected int id;
protected String name;
....
}
@Entity
public class ExampleClass extends GeneralData {
...
}
而第二个映射是
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class GeneralData implements Serializable {
....
}
@Entity
public class ExampleClass extends GeneralData {
...
}
亲爱的未来reader:在完成
我有一个 abstract
class,其中包含我希望在我的所有实体中拥有的一些基本值(例如 ID、创建日期、创建用户等)。目前,我正在为每个具体 class 具有 table 并使其 id 工作的组合而苦苦挣扎。
看来我可以有一个 table 每个 class 或一个我配置 ID 的地方,但不能同时有两个。这对我来说似乎很奇怪而且不太可能,所以我想确保情况确实如此。
可能相关的版本:hibernate 5、mysql 5.5、java 1.8、spring 4.3。
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@MappedSuperclass
public abstract class GeneralData implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(nullable = false)
protected int id;
protected String name;
// getters, setters, constructors, etc.
}
示例子class:
@Entity
public class ExampleClass extends GeneralData {
// own values, constructors, getters, setters, etc.
}
我得到的错误:
Cannot use identity column key generation with <union-subclass> mapping for: org.example.ExampleClass
我尝试过的事情:
- 我曾尝试将
GeneralData
变成@Entity
,但这没有帮助。 - I tried to 使用
GenerationType.TABLE
但由于密钥太大而失败。 (另外,我宁愿不要这个,IDENTITY 是我想要的)错误:Specified key was too long; max key length is 1000 bytes
我不想将 id 列移动到每个具体 class。如果 ID 仅对单个 table 而不是整个依赖树唯一,我完全没问题。
如果我应该升级我的库、数据库等,请记住,这只能通过大量额外的工作来完成(出于内部原因)。这将是最后的手段,我希望首先看到一些它有帮助的证据。
对同一父实体的所有子对象的要求是它们之间具有唯一的 ID。
例如,假设您有一个父实体 GeneralData
,然后使用 id=1 存储子类型 A
。
这将是完全合法的:
GeneralData loaded = entitymanager.find( GeneralData.class, 1 );
当然 loaded
的类型将是 A
:子类。 映射必须确保没有歧义:不允许其他子类也使用“1”作为 ID,即使它映射到不同的 table。
在你的例子中,你要求 Hibernate 将 GeneralData
的每个不同子类型存储到它自己单独的 Table.
您还要求 MySQL - 它不知道这些 table 以任何方式相关 - 自动分配唯一标识符。
无法指示 MySQL 这些 table 中的每一个都需要使用相同的 Identity
"sequence",因为它们不是真正的序列:因此此映射是非法的!这会给您带来麻烦,因为它会将重叠 ID 分配给父实体的不同子类型,这违反了上述语义。
这是使用 IDENTITY 的局限性的一个很好的例子;此外,IDENTITY 不是很有效,因为它意味着 Hibernate 需要在实体持久化后立即写入实体,而不是能够更有效地将刷新操作推迟到更合适的时间,因此可能会批量写入或完全跳过它们(特别是如果事务被中止,而且如果您在持久化之后更新实体但仍在同一事务中)。
我建议看看不同的 Identifier generator strategies for such hierarchies, and in particular Optimizers 可能会大大提高您的应用程序的性能。
每个具体 class 映射可以有 2 个不同的 table :
- 对于隐式多态性,无法使用多态查询,但您可以使用 IDENTITY 策略(正如 Sanne 指出的那样效率不高)。标识符可以在 superclass 或 subclasses. 中定义
- with union, 不允许 IDENTITY 策略(Sanne 已经清楚地解释了原因)。标识符必须在 superclass 中定义
第一个映射是
@MappedSuperclass
public abstract class GeneralData implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(nullable = false)
protected int id;
protected String name;
....
}
@Entity
public class ExampleClass extends GeneralData {
...
}
而第二个映射是
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class GeneralData implements Serializable {
....
}
@Entity
public class ExampleClass extends GeneralData {
...
}