0

エンティティ(MyEntity)に次のフィールドがあります。

@OneToMany(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
@JoinColumn(name="ID", referencedColumnName="ID")
@MapKey(name="localeForDB")
private Map<String, MyEntityTranslations> translations;

MyEntityTranslationsは次のようになります。

@Entity
@Table(name="MY_ENTITY_TRANSLATIONS")
public class MyEntityTranslations extends CustomTranslations
{
    private String prop1;
    private String prop2;

    //..getters and setters
}

そして最後に、CustomTranslationsは次のようになります。

@MappedSuperclass
@Access(AccessType.FIELD)
public abstract class CustomTranslations
{
    @Id
    protected Long id;
    @Transient
    protected Locale locale;

    @Column(name="LOCALE", nullable=false)
    @Access(AccessType.PROPERTY)
    @Id
    protected String getLocaleForDB()
    {
        return locale.toString();
    }

    protected void setLocaleForDB(String localeFromDB)
    {
        //logic for creating a Locale object from a String
    }
}

データベースからデータを引き出すときは、すべてがうまく機能します。MyEntityを取得すると、期待どおりにマップにデータが入力されます。ただし、データを挿入(MyEntityを保存)しようとすると、エラーが発生します。これはログにあるものです:

[EL Fine]: 2012-09-04 23:40:19.989--ClientSession(101408113)--Connection(1411623120)--Thread(Thread[http-8080-1,5,main])--select nextval(MY_ENTITY_SEQ_GEN)
[EL Fine]: 2012-09-04 23:40:20.048--ClientSession(101408113)--Connection(1411623120)--Thread(Thread[http-8080-1,5,main])--INSERT INTO MY_ENTITY (ID, STUFF, FOR, MY_ENTITY,) VALUES (?, ?, ?, ?)
    bind => [1, foo1, foo2, foo3]
[EL Fine]: 2012-09-04 23:40:20.13--ClientSession(101408113)--Connection(1411623120)--Thread(Thread[http-8080-1,5,main])--INSERT INTO MY_ENTITY_TRANSLATIONS (ID, LOCALE, PROP1, PROP2) VALUES (?, ?, ?, ?)
    bind => [null, en_US, My Prop1, My Prop2]
[EL Fine]: 2012-09-04 23:40:20.135--ClientSession(101408113)--Thread(Thread[http-8080-1,5,main])--SELECT 1
[EL Warning]: 2012-09-04 23:40:20.139--UnitOfWork(1394902291)--Thread(Thread[http-8080-1,5,main])--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: null value in column "id" violates not-null constraint
Error Code: 0
Call: INSERT INTO MY_ENTITY_TRANSLATIONS (ID, LOCALE, PROP1, PROP2) VALUES (?, ?, ?, ?)
    bind => [null, en_US, My Prop1, My Prop2]
Query: InsertObjectQuery(com.foo.MyEntityTranslations@53fd3a3b)
Sep 4, 2012 11:40:54 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet appServlet threw exception
org.postgresql.util.PSQLException: ERROR: null value in column "id" violates not-null constraint
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2103)

ここで、オブジェクトを保存しようとする前にMyEntity、エントリのidフィールドMyEntityTranslationsがnullであることがマップに表示されます。MyEntityそれ自体はまだIDを持っていないので、私はこれを理解しています。のidフィールドにMyEntityは、次のアノテーションがあります。

@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="MY_ENTITY_SEQ_GEN")

したがって、挿入時にシーケンスからIDを取得します。私の質問は、そのIDもレコードにMyEntityTranslations記録されるように、マップにどのように注釈を付ける必要があるかということです。でさまざまな属性を試しました@JoinColumnが、何も機能しないようです。私はJPAの初心者なので、明らかな何かが欠けている可能性があります。すべてのJPA実装を独立させたいのですが、それが重要な場合は、EclipseLink2.3.2を使用しています。

以下の提案に基づいて、CustomTranslationsを次のように変更しました。

@MappedSuperclass
@Access(AccessType.FIELD)
public abstract class CustomTranslations<T>
{
    @Id
    @ManyToOne
    @JoinColumn(name="ID")
    protected T translationsFor;
    @Transient
    protected Locale locale;

    @Column(name="LOCALE", nullable=false)
    @Access(AccessType.PROPERTY)
    @Id
    protected String getLocaleForDB()
    {
        return locale.toString();
    }

    protected void setLocaleForDB(String localeFromDB)
    {
        //logic for creating a Locale object from a String
    }
}

そして、私のマップはMyEntity次のようになります。

@OneToMany(mappedBy="translationsFor", fetch=FetchType.EAGER, cascade=CascadeType.ALL)
@MapKey(name="localeForDB")
private Map<String, MyEntityTranslations> translations;

何かを誤解していると確信していますが、MyEntityインスタンスを保存しようとすると、以前とまったく同じエラーが発生します。

4

2 に答える 2

1

MyEntityTranslationsに@ManyToOneが必要です。@OneToManyは、@JoinColumnではなくmappedByを使用する必要があります。

CustomTranslationsからIDを削除し、代わりに@JoinColumnと@Idを含む@ManyToOneをMyEntityに追加します。

http://en.wikibooks.org/wiki/Java_Persistence/OneToManyを参照してください 。

および、 http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#JPA_2.0

于 2012-09-05T13:49:28.457 に答える
0

「MY_ENTITY_TRANSLATIONS」テーブルの「ID」フィールドを制御する2つのマッピングがあるため、これによりエラーが発生するはずです。1つ目はCustomTranslationsクラスのIDマッピングであり、2つ目はMyEntityのOneToManyマッピングです。書き込み可能なものは1つだけです。他の問題を回避するために、テーブルにマップされたクラス内から1つにアクセスできるようにすることをお勧めします。

必要なことを行う最も簡単な方法は、OneToManyを双方向のOneToManyにすることです。つまり、CustomTranslationsのManyToOneマッピングをMyEntityに追加し、「ID」フィールドを結合列として使用してから、OneToManyをこの新しいマッピングによってマッピングされたものとしてマークします。JPAでは、この新しいManyToOneをCustomTranslationsのIDとして作成できるため、Long IDを削除するか、Long IDを保持して@MapsIdアノテーションを使用し、参照されたMyEntityの値がで使用されることをJPAが認識できるようにすることができます。ロングIDフィールドも同様です。何かのようなもの:

   @Id protected Long id;  
   @MapsId(value="id")
   @ManyToOne
   MyEntity myEntityBackReference;   

コレクションだけでなく双方向の関係を維持する必要がありますが、これは実装に依存しません。

于 2012-09-05T13:50:20.767 に答える