Спящий режим и без ПК

Возможно ли создать таблицу (из JPA аннотированного Hibernate @Entity), которая не содержит первичный ключ /Id?

Я знаю, что это не очень хорошая идея; таблица должна иметь первичный ключ.

Ответ 1

Я обнаружил, что это невозможно сделать. Настолько неудача для тех, кто работает с устаревшими системами.

Если вы перепроектируете (создаете аннотированные объекты JPA из существующего соединения JDBC), таблица создаст два класса Java, одну Entity и одно поле; id и один внедряемый id, содержащий все столбцы из вашего отношения.

Ответ 2

Автоответчик Роджера правильный. Чтобы немного рассказать о том, что имеется в виду (сначала я не понял его и подумал, что это поможет):

Скажем, у вас есть таблица 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 на два:

@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 будет использовать ключ Embeddable для его необходимой идентификации, и вы можете сделать вызов как обычно:

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

Надеемся, что это поможет первоклассникам с этим работать.

Ответ 3

Использовать следующий код; 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;    
  }
}

Ответ 4

Я обнаружил, что этот трюк работает:

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

Ответ 5

Вам не нужно создавать отдельный класс для вашего @Id или основного ключа. Просто используйте Integer (или что-то еще). Кроме того, не публикуйте поддельный ключ, так как разработчики, которые его используют, могут подумать, что это реально и в противном случае пытаются его использовать. Наконец, это лучше всего использовать в 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;    
  }


}

Ответ 6

Создать Pojo из таблицы - используйте обратный инженерный метод, существующий в eclipse. Для таблицы не первичных ключей eclipse будет генерировать два класса 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());
            }
        }      
}

Ответ 7

Добавление в комментарий Awied. Если вы хотите найти панель, используйте следующий HQL.

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

Ответ 8

Когда дело доходит до представлений вместо поиска обходных путей в Hibernate, может быть проще добавить фиктивный идентификатор в вашем представлении базы данных. Я написал об этом в другом вопросе: fooobar.com/questions/115565/...

Ответ 9

Я нашел решение для таблиц без первичного ключа и null в качестве значений. Он будет работать на базе Oracle. Возможно, что-то подобное существует для других БД.

  • Вы должны создать новый первичный ключ в классе POJO:

    @Id @column (name= "идентификатор" ) private Integer id;

и используйте createNativeQuery, подобный этому

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

Собственный запрос будет генерировать первичный ключ, и вы получите уникальные результаты.