web-dev-qa-db-ja.com

休止状態およびPKなし

テーブルを作成することは可能ですか(JPAアノテーション付きHibernate @Entity)主キー/ IDが含まれていない?

これは良い考えではないことを知っています。テーブルには主キーが必要です。

52
Schildmeijer

そうすることは不可能であることがわかりました。レガシーシステムで作業している人には不運です。

リバースエンジニアリング(既存のJDBC接続からJPAアノテーション付きエンティティを作成)する場合、テーブルは2つのJavaクラス、1つのエンティティと1つのフィールド、ID、およびすべての列を含む1つの埋め込み可能なID関係。

9
Schildmeijer

ロジャーの自己回答は正しい。意味を少し詳しく説明するには(最初は明確ではありませんでしたが、これが役立つと考えました):

テーブルFooを持っているとしましょう:

TABLE Foo (
bar varchar(20),
bat varchar(20)
)

通常、このテーブルで機能するクラスw/Annotationsを作成できます。

// Technically, for this example, the @Table and @Column annotations 
// are not needed, but don't hurt. Use them if your column names 
// are different than the variable names.

@Entity
@Table(name = "FOO")
class Foo {

  private String bar;
  private String bat;


  @Column(name = "bar")
  public String getBar() {
   return bar;    
  }

  public void setBar(String bar) {
   this.bar = bar;    
  }

  @Column(name = "bat")
  public String getBat() {
   return bat;    
  }

  public void setBat(String bat) {
   this.bat = bat;    
  }

}

..しかし、くそー。このテーブルにはIDとして使用できるものは何もありません。これは[重要なビジネス関数を挿入]に使用するレガシーデータベースです。休止状態を使用するためにテーブルの変更を開始できるとは思わない。

代わりに、行全体をキーとして使用できるように、オブジェクトを休止状態で実行可能な構造に分割できます。 (当然、これは行が一意であることを前提としています。)

Fooオブジェクトを次のように2つに分割します。

@Entity
@Table(name = "FOO")
class Foo {

  @Id
  private FooKey id;

  public void setId(FooKey id) {
    this.id = id;
  }

  public void getId() {
    return id;
  }
}

そして

@Embeddable
class FooKey implements Serializable {
  private String bar;
  private String bat;

  @Column(name = "bar")
  public String getBar() {
   return bar;    
  }

  public void setBar(String bar) {
   this.bar = bar;    
  }

  @Column(name = "bat")
  public String getBat() {
   return bat;    
  }

  public void setBat(String bat) {
   this.bat = bat;    
  }

}

..そしてそれはそれであるはずです。 Hibernateは、必要なIDにEmbeddableキーを使用し、通常どおり呼び出しを行うことができます。

Query fooQuery = getSession().createQuery("from Foo");

これが初めての人がこれを機能させるのに役立つことを願っています。

50
awied

次のコードを使用します。 Hibernateには、重複レコードを区別する独自のロジックがありません

このアプローチに問題があるかどうかを教えてください

@Entity @IdClass(Foo.class)
class Foo implements Serializable {
  @Id private String bar;
  @Id private String bat;

  public String getBar() {
   return bar;    
  }

  public void setBar(String bar) {
   this.bar = bar;
  }


  public String getBat() {
   return bat;    
  }

  public void setBat(String bat) {
   this.bat = bat;    
  }
}
45
Amit

私はこのトリックが機能することがわかりました:

<id column="ROWID" type="string" />
9
RudiDudi

@Idまたは主キーとして別のクラスを作成する必要はありません。整数(または何でも)を使用してください。また、偽のキーを使用する開発者はそれが本物であると考え、別の方法で使用しようとする可能性があるため、偽のキーを公開しないでください。最後に、これはVIEWでの使用が最適です。すべてではないにしても、ほとんどの場合、テーブルに主キーが必要であるという以前の投稿に同意します。例えば:

@Entity
@Table(name = "FOO")
class Foo {

  @SuppressWarnings("unused")
  @Id
  private Integer id;

  @Column(name = "REAL_COLUMN")
  private String realColumn;

  public String getRealColumn() {
    return realColumn;    
  }

  public void setRealColumn(String realColumn) {
    this.realColumn= realColumn;    
  }


}
2
Domenic D.

Awiedのコメントに追加。バーを検索する場合は、次のHQLを使用します。

Query fooQuery = getSession().createQuery("from Foo.id.bar = '<barName>'");
1
punkck

テーブルからPojoを作成するには-Eclipseに存在するリバースエンジニアリングメソッドを使用します。非主キーテーブルの場合、Eclipseは2つのPojoクラスを生成します。

Eclipse generated class and hbm.xml - 
---
Foo.Java 
//

public class Foo implements Java.io.Serializable {

    private FooId id;

    public Foo() {
    }

    public Foo(FooId id) {
        this.id = id;
    }

    public FooId getId() {
        return this.id;
    }

    public void setId(FooId id) {
        this.id = id;
    }

}
---
FooId.Java
//

public class FooId implements Java.io.Serializable {

    private String bar;
    private String bat;

    public FooId() {
    }

    public FooId(String bar, String bat) {
        this.bar = bar;
        this.bat = bat;
    }

    public String getBar() {
        return this.bar;
    }

    public void setBar(String bar) {
        this.bar = bar;
    }

    public String getBat() {
        return this.bat;
    }

    public void setBat(String bat) {
        this.bat = bat;
    }

    public boolean equals(Object other) {
        if ((this == other))
            return true;
        if ((other == null))
            return false;
        if (!(other instanceof FooId))
            return false;
        FooId castOther = (FooId) other;

        return ((this.getBar() == castOther.getBar()) || (this.getBar() != null
                && castOther.getBar() != null && this.getBar().equals(
                castOther.getBar())))
                && ((this.getBat() == castOther.getBat()) || (this.getBat() != null
                        && castOther.getBat() != null && this.getBat().equals(
                        castOther.getBat())));
    }

    public int hashCode() {
        int result = 17;

        result = 37 * result
                + (getBar() == null ? 0 : this.getBar().hashCode());
        result = 37 * result
                + (getBat() == null ? 0 : this.getBat().hashCode());
        return result;
    }

}
---
Foo.hbm.xml

<hibernate-mapping>
    <class name="com.Foo" table="foo" schema="public" catalog="hibernate_poc">
        <composite-id name="id" class="com.FooId">
            <key-property name="bar" type="string">
                <column name="bar" length="20" />
            </key-property>
            <key-property name="bat" type="string">
                <column name="bat" length="20" />
            </key-property>
        </composite-id>
    </class>
</hibernate-mapping>

---
entry in the Hibernate.cfg.xml - 

<mapping class="com.poc.Foo" resource="Foo.hbm.xml"/>

---
Fetch the Data from table -
FooDataFetch.Java
//

import Java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

public class FooDataFetch {
        private static Session session = null;

   public static void main(String[] args) {
          try{            
            Configuration cfg = new Configuration();
            cfg.configure("/hibernate.cfg.xml");
            SessionFactory sf = cfg.buildSessionFactory();
            session = sf.openSession();

            session.beginTransaction();
              queryPerson(session);
            session.close(); 

          }catch (Throwable ex) { 
             System.err.println("Failed to create sessionFactory object." + ex);
            ex.printStackTrace();
             throw new ExceptionInInitializerError(ex); 
          }       
       }    

       private static void queryPerson(Session session) {
            Query query = session.createQuery("from Foo");                 
            List <Foo>list = query.list();
            Java.util.Iterator<Foo> iter = list.iterator();
            while (iter.hasNext()) {
                Foo foo = iter.next();
                System.out.println("Foo Details: \"" + foo.getId().getBar() +"\", " + foo.getId().getBat());
            }
        }      
}
1
Kuldeep

Hibernateで回避策を検索するのではなく、ビューに関しては、データベースビューにダミーIDを追加する方が簡単な場合があります。別の質問でそれについて書いた: https://stackoverflow.com/a/44050230/1673775

1
luke

ROWIDは疑似列ですが、ROWIDはROWの物理アドレスに対応しますが、行データを取得する最も速い手段です。 @Idはオブジェクトを一意に識別するために使用され、ROWIDはテーブル内で一意であるため、これを利用して、議論している問題を克服できます。実際、意味のある一意の識別子を必要としない場合、ROWIDは、行の物理アドレスに対応するため、@ Id注釈を付けるのに最適な列です。次のコードは私のために働いた。 @Id @Column(name = "ROWID") private String Id;

0

主キーがなく、値がnullのテーブルのソリューションを見つけました。 Oracle DBで動作します。他のDBにも同様のことが存在する可能性があります。

  1. POJOクラスに新しい主キーを作成する必要があります。

    @Id @Column(name = "id")private整数id;

このようにcreateNativeQueryを使用します

getEntityManager().createNativeQuery("select rownum as id, .....

ネイティブクエリは主キーを生成し、一意の結果を取得します。

0
Kanaris007