java 没有鉴别器列的单表继承
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6572814/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Single Table Inheritance WITHOUT Discriminator column
提问by MountainBeast
Good Morning, my Dear comrades,
早上好,我亲爱的同志们,
This is starting to be come annoying - a simple thing, but hours of struggle, am I getting old??
这开始变得烦人 - 一件简单的事情,但经过数小时的斗争,我变老了吗??
I am trying to map two Classes to a single table using JPA by Hibernate. The idea is to have only a small subset of columns in parent Class, and bigger/full set in the child Class. There is NO TABLE inheritance involved, only class inheritance. How can this be accomplished??
我正在尝试使用 Hibernate 的 JPA 将两个类映射到一个表。这个想法是在父类中只有一小部分列,在子类中设置更大/完整的列。不涉及 TABLE 继承,只涉及类继承。这怎么能实现??
Doing this will not work:
这样做是行不通的:
@Entity
@Table(name = "the_table")
class Parent implements Serializable {
}
@Entity
@Table(name = "the_table")
class Child extends Parent implements Serializable {
}
Hibernate assumes default inheritance strategy InheritanceType.SINGLE_TABLE, and is looking for discriminator column - DTYPE by default. But wait - there is no table inheritance, having the discriminator column does not make sence.
Hibernate 假定默认继承策略 InheritanceType.SINGLE_TABLE,并且默认查找鉴别器列 - DTYPE。但是等等 - 没有表继承,有鉴别器列没有意义。
I have also taken a look at PolymorphismType.EXPLICIT which did not make any difference. The stack trace is:
我还查看了 PolymorphismType.EXPLICIT,它没有任何区别。堆栈跟踪是:
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'apprentice0_.DTYPE' in 'where clause'
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
at com.mysql.jdbc.Util.getInstance(Util.java:386)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1052)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3597)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3529)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1990)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2151)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2625)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2119)
at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:2281)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeQuery(NewProxyPreparedStatement.java:76)
at org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:208)
at org.hibernate.loader.Loader.getResultSet(Loader.java:1808)
at org.hibernate.loader.Loader.doQuery(Loader.java:697)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259)
at org.hibernate.loader.Loader.loadEntity(Loader.java:1881)
yeah, one more thing:
是的,还有一件事:
The @MappedSuperclass
and @Embeddable
are of no use as these can not be used in conjunction with @Entity
- the parent class has to be an @Entity
itself as it is being used for persistence elsewhere.
的@MappedSuperclass
和@Embeddable
是没有用的,因为这些不能与结合使用@Entity
-父类有一个是@Entity
本身因为它是被用于持久性别处。
回答by JB Nizet
@MappedSuperclass
is the annotation that must be used. If the same class is both a mapped super class and an entity, then simply split it into two classes:
@MappedSuperclass
是必须使用的注解。如果同一个类既是映射的超类又是实体,则只需将其拆分为两个类:
@MappedSuperclass
public class Parent {
// ...
}
@Entity
public class ParentEntity extends Parent {
// no code at all here
}
@Entity
public class Child extends Parent {
// additional fields and methods here
}
回答by user2219808
There are a couple of ways each with their own caveats.
有几种方法,每种方法都有自己的注意事项。
1) Add annotations as following:
1)添加注释如下:
@DiscriminatorFormula("0")
@DiscriminatorValue("0")
class BaseClass{ }
@DiscriminatorValue("00")
class SubClass extends BaseClass{ }
where the subclasses discriminator value must be different to the base class' but also evaluate to the same value when passed into an Integer.valueOf(String s) method.
其中子类鉴别器值必须与基类不同,但在传递到 Integer.valueOf(String s) 方法时也评估为相同的值。
The caveat - if you return an object from Hibernate of the base class and then again when calling for the subclass type you will get an error complaining the loaded object was of the wrong class. If you call the subclass query first however the base class call will return the subclass.
警告 - 如果您从基类的 Hibernate 返回一个对象,然后在调用子类类型时再次返回一个对象,您将收到一个错误,抱怨加载的对象属于错误的类。如果您首先调用子类查询,则基类调用将返回子类。
2) Use a view in the database to map the table and use this as the table of the sub class. In fact it can be any other class that matches the column mappings as Hibernate thinks its a completely separate table.
2)使用数据库中的一个视图来映射表,并将其作为子类的表。事实上,它可以是与列映射匹配的任何其他类,因为 Hibernate 认为它是一个完全独立的表。
Caveat - You will potentially have the same row instantiated as two different objects that will not be synchronised and could lead to conflicting/lost database updates.
警告 - 您可能会将同一行实例化为两个不同的对象,这些对象不会同步并可能导致冲突/丢失数据库更新。
It's probably better to stick with one type for a session and that could be handled without the runtime risks by using an entity mapping xml file that overrides the DiscriminatorValue of the desired class to match the constant Discriminator'Formula' value which you can pass into the initial configuration.
最好为会话坚持使用一种类型,并且可以通过使用实体映射 xml 文件覆盖所需类的 DiscriminatorValue 以匹配常量 Discriminator'Formula' 值来处理,而不会产生运行时风险,您可以将其传递给初始配置。
回答by tvanfosson
Make a view of the table with the limited set of columns and map the second class to that one. Define an interface with the limited set of columns and have both class implement the interface. That probably gets you about 95% of what you need. If you need to, create methods to define equality between the two as well as being able to convert the larger class (via a constructor?) to the smaller class.
使用有限的一组列查看表并将第二个类映射到那个类。定义一个具有有限列集的接口,并让两个类都实现该接口。这可能会为您提供大约 95% 的所需内容。如果需要,创建方法来定义两者之间的相等性以及能够将较大的类(通过构造函数?)转换为较小的类。
回答by Bozho
You have to select an inheritance type for two entities.
您必须为两个实体选择一个继承类型。
What you are trying to do is not appropriate, because hibernate won't know what objects to instantiate.
您尝试做的事情不合适,因为休眠不知道要实例化哪些对象。
If you simply need an object to have fewer fields, then don't map it as an entity - just provide a constructor that copies all fields from the other class.
如果您只需要一个对象具有较少的字段,则不要将其映射为实体 - 只需提供一个构造函数来复制其他类的所有字段。
回答by Neal.Shan
If you don't want to add auto dtype column, you should define your own Discriminator by @DiscriminatorFormula
如果您不想添加自动 dtype 列,则应通过 @DiscriminatorFormula 定义自己的鉴别器
@Entity
@Table(name = "CS_CUSTOMER")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorFormula("case when id < 3 then 'VIP' else 'Customer' end")
public class Customer extends BaseEntity {
...
@Entity
public class VIP extends Customer {
...
The Discriminator name is default to Entity class name, if you want to change it, use
Discriminator 名称默认为实体类名称,如果要更改它,请使用
@DiscriminatorValue("VIP")
Log from hibernate
从休眠登录
Hibernate: create sequence hibernate_sequence start with 1 increment by 1
Hibernate:
create table cs_customer (
id bigint not null,
create_user_id bigint,
first_name varchar(255),
last_name varchar(255),
primary key (id)
)