Spring 3.2.1、Hibernate 4.1.9、および Spring Data アプリケーションがあります。エンティティに結合された継承タイプを使用しています。階層は次のとおりです。スーパークラス DomainEntity と、それを継承し、他のクラスによって継承される 2 つのクラス SmartElement および LowLevelEntity です。SmartElement には LowLevelEntities のセットがあり、関係は双方向です。
DomainEntity クラス
@Entity
@Table(name = "entity")
@Inheritance(strategy = InheritanceType.JOINED)
public class DomainEntity implements Serializable
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "entity_id", unique = true)
private long uuid;
@Column(name = "entity_name", unique = true)
protected String name;
@ManyToOne()
@JoinColumn(name = "location_id")
protected Location location;
@ManyToOne(cascade = {CascadeType.ALL})
@JoinColumn(name = "state_id")
protected State state;
// getters and setters
}
SmartElment クラス
@Entity
@Table(name = "smart_element")
@Inheritance(strategy = InheritanceType.JOINED)
@PrimaryKeyJoinColumn(name = "smart_element_id")
public class SmartElement extends DomainEntity implements Serializable
{
@OneToMany (mappedBy = "connectedEntity",
cascade = {CascadeType.ALL}, orphanRemoval = true)
protected Set<LowLevelEntity> lowLevelEntityCollection;
// getters and setters
}
そして LowLevelEntity クラス
@Entity
@Table(name = "low_level_entity")
@Inheritance(strategy = InheritanceType.JOINED)
@PrimaryKeyJoinColumn(name = "low_level_entity_id")
public class LowLevelEntity extends DomainEntity implements Serializable
{
@ManyToOne()
@JoinColumn(name = "smart_element_id")
protected SmartElement connectedEntity;
public void setConnectedEntity(SmartElement connectedEntity)
{
if (connectedEntity != null)
{
this.connectedEntity = connectedEntity;
this.connectedEntity.addLowLevelEntity(this);
} else
{
if (this.connectedEntity != null)
{
this.connectedEntity.removeLowLevelEntity(this);
}
this.connectedEntity = connectedEntity;
}
// other fields and getters/setters
}
SmartElement から継承するクラスの 1 つは非常に単純で、Lighting クラスです。
@Entity
@Table(name = "lighting")
@PrimaryKeyJoinColumn(name = "lighting_id")
public class Lighting extends SmartElement implements Serializable
{
@Enumerated(EnumType.STRING)
protected LightingLevelType lightingLevel = LightingLevelType.NONE;
public LightingLevelType getLightingLevel()
{
return lightingLevel;
}
public void setLightingLevel(LightingLevelType lightingLevel)
{
this.lightingLevel = lightingLevel;
}
}
LightingLevel は列挙型クラスです
public enum LightingLevelType
{
NONE(0), QUARTER(0.25), HALF(0.5), THREE_QUARTERS(0.75), MAX(1);
private double value;
private LightingLevelType(double value)
{
this.value = value;
}
public double getValue(){
return value;
}
}
次を実行するたびにエラーが発生します
SmartElement element = new Lighting("lamp", new SmartElementState(), kitchen);
//fields inherited from the superclass DomainEntity name, state and location
LowLevelEntity sensor = new LowLevelEntity("sensor", new SensorState(), kitchen);
sensor.setConnectedEntity(element);
Spring Data JPARepository 保存メソッドを使用して格納場所を永続化することにより、エンティティをカスケード経由で保存します。
エラーは言う:
could not get a field value by reflection getter of model.highlevel.smartelement.lighting.Lighting.lightingLevel;
同じコードを実行して Lighting を SmartElement に変更すると、エラーは発生しません
SmartElement element = new SmartElement("lamp", new SmartElementState(), kitchen);
行をコメントしても発生しませんsensor.setConnectedEntity(element);
場合によっては、Lighting インスタンスの別の名前でエラーが発生しないことがあり、equals および hashCode メソッドの実装に問題があるのではないかと考えました。hereのように、またはIDなしで要素の名前を使用するだけで、これに対してさまざまなアプローチを試みましたが、それでもエラーが発生しました。
@Override
public boolean equals(final Object other)
{
if (this == other) return true;
if (! (other instanceof DomainEntity)) return false;
DomainEntity castOther = (DomainEntity) other;
return new EqualsBuilder()
.append(name, castOther.name).isEquals();
}
@Override
public int hashCode()
{
return new HashCodeBuilder()
.append(name).toHashCode();
}
私は単に何が起こっているのか、何が間違っているのかを理解していません。誰かが何らかの考えを持っているか、そのようなケースに遭遇した場合、私はその情報に非常に感謝しています. 長文で申し訳ありませんが、コードもあると分かりやすいと思います。
アップデート
エラーの原因を突き止めるために、いくつかのことを試しました。
- LightingLevelType クラスのタイプをプレーンに変更しても効果はなく、エラーは引き続き発生します。
- Lighting クラスのフィールドを に変更して
public int type
も効果はなく、削除するだけでエラーが修正されますが、それはオプションではありません。 - LowLevelEntity オブジェクトで connectedEntity フィールドを設定しようとすると、エラーが発生
sensor.setConnectedEntity(element);
しthis.connectedEntity = connectedEntity
ます。オブジェクトを SmartElement セットに追加するだけで、逆の関係を設定しない場合、エラーは発生しませんが、connectedEntity は null になります。データベースから両方のオブジェクトを取得した場合、逆の関係を設定して再度保存すると、エラーは表示されません。
したがって、これは、まだ永続化されていないエンティティを含む関係 (私が間違っていなければ LowLevelEntity クラスが所有者です) の所有部分に接続を設定し、エンティティを保存することに関係があると考える傾向があります。その場所からカスケード経由で。奇妙なことに、@Repeat(50) を使用してこのテストを実行したばかりですが、smartElement の名前を「ランプ」から「kitchen_lamp」に変更しただけです。
SmartElement element = new Lighting("kitchen_lamp", new SmartElementState(), kitchen);
LowLevelEntity lamp_kitchen = new LowLevelEntity("lamp_kitchen", new SensorState(), kitchen);
エラーなし。また、コンソールで、スマート要素に「kitchen_lamp」以外の名前が付いている場合、hibernate は最初に LowLevelEntity を挿入してから smartElement を挿入しようとし、「kitchen_lamp」という名前で挿入を逆にしますが、エラーは発生しません。なぜこれが起こるのか、そしてこれについて私にできることがあるかどうか誰かが知っていますか?