2017-02-03 7 views
2

私は現在、SQL Server 2016/Azure SQL ServerとインターフェイスするためにHibernateを使用しています。私のデータベースでは、システムのバージョン管理された一時テーブルを実装しました。私は、適切なテーブルの一時的な履歴から元のValidFromとUpdatedByフィールドを表す私のHibernateエンティティにのみ注釈で2つの変数をマッピングしたい(できれば遅延して)。Hibernate sql annotation

たとえば、アカウントのクラスとテーブルがあります。次のようにアカウント[マイナスなどの非関連列、制約、表は次のとおりです。

CREATE TABLE [dbo].[Account] (
[Id]   INT           IDENTITY (1, 1) NOT NULL, 
[UpdatedBy] INT           NOT NULL, 
[ValidFrom] DATETIME2 (7) GENERATED ALWAYS AS ROW START DEFAULT (sysutcdatetime()) NOT NULL, 
[ValidTo]  DATETIME2 (7) GENERATED ALWAYS AS ROW END DEFAULT (CONVERT([datetime2],'9999-12-31 23:59:59.9999999')) NOT NULL, 
CONSTRAINT [FK_Account.UpdatedById_Account.Id] FOREIGN KEY ([UpdatedBy]) REFERENCES [dbo].[Account] ([Id]), 
PRIMARY KEY CLUSTERED ([Id] ASC), 
PERIOD FOR SYSTEM_TIME ([ValidFrom], [ValidTo]) 
) 
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE=[dbo].[AccountHistory], DATA_CONSISTENCY_CHECK=ON)); 

私が望むデータを取得するためのSQL文は、(私は、私は、注釈ごとにのみUpdatedByまたはValidFromを選択するだろうと想像し、このようになります。しかし、彼らは簡潔にするために、今一緒にいる):

SELECT UpdatedBy, ValidFrom FROM dbo.Account 
FOR SYSTEM_TIME ALL 
WHERE ValidFrom IN 
(
SELECT MIN(ValidFrom) OVER (Partition BY Id) AS ValidFrom 
FROM dbo.Account 
FOR SYSTEM_TIME ALL 
WHERE ID = $(passedInIdOfThisEntity) 
) 

最後に、私のHibernateのエンティティ/ POJOは、この(再)無関係な変数をredactingのようなものになります。私は肝炎

@Entity 
@Table(name = "Account") 
public class Account implements Serializable { 

    @Id 
    @Column(name = "Id", unique = true, nullable = false) 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private int id; 

    @ManyToOne(fetch = FetchType.LAZY) 
    @JoinColumn(name = "UpdatedBy") 
    private Account updatedBy; 

    @Temporal(TemporalType.TIMESTAMP) 
    @Column(name = "ValidFrom", nullable = false, length = 27, insertable = false, updatable = false) 
    private Date validFrom; 

    @Temporal(TemporalType.TIMESTAMP) 
    @Column(name = "ValidTo", nullable = false, length = 27, insertable = false, updatable = false) 
    private Date validTo; 

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "updatedBy") 
    private Set<Account> accountsUpdated; 

    // This is a stub of what I'm hoping you can help me add 
    @Temporal(TemporalType.TIMESTAMP) 
    @Column(name = "ValidFrom", fetch = FetchType.LAZY, insertable = false, updatable = false, somesqlselect = SQL_STATEMENT_FROM_ABOVE) 
    private Date createdOn; 

    @Column(name = "UpdatedBy", fetch = FetchType.LAZY, insertable = false, updatable = false, somesqlselect = SQL_STATEMENT_FROM_ABOVE) 
    private Account createdBy 

    // ... getters and setters below 
} 

を私はHibernateを大部分使用していましたが、これに関する情報を見つけるのは困難でしたが、基準クエリを使用する代わりにエンティティを取得するためのネイティブクエリを実装する例を見つけて使用しました。この謎を解きほぐして、基準クエリを使用してデータを取得し、必要に応じてアノテーションを使用してこれらのフィールドにデータを入力し続けることができれば、私は大いに感謝します。

+0

あなたが望むものを理解したら、@ManyToOneを実行してネイティブサブクエリを持つ単一の列値にするのではなく、別のテーブルをマップする必要があります。 – JustinKSU

+0

AccountHistoryへのマッピングを持つアカウントoriginalAccountを持っているとしますか?私はそれがうまくいくかどうかはわかりません。なぜなら、履歴テーブルは、メインテーブルを介して間接的にプロキシによって照会されることになっているからです。履歴テーブルにはPKはありません。書き込みはできません。時間ベースのクエリダイアログはすべて親テーブルのアカウントでのみ動作します。私がSQLクエリを使って新しいエンティティをマッピングしたのであれば、そのように遅延ロードを行うことができるかもしれません。 – Proto

+0

ああ、私は今参照してください。私はあなたのベスト・ベットがネイティブ・クエリーにあると思うhttps://docs.jboss.org/hibernate/orm/3.6/reference/en-US/html/querysql.html – JustinKSU

答えて

0

あなたが記述した一時テーブルの構造体は、JPAやHibernateのネイティブサポートがわかっているものではありません。これらはANSI SQL標準の新機能であり、適切なサポートには至っていません。

これは、タスクを達成するためにHibernateのようなフレームワークを使用できないというわけではありません。コメントに示されているように、名前付きクエリを指定して実行して、必要な属性を取得することができます。

JPA 2.1の観点からは、@SqlResultSetMapping@ConstructorResultを使用します。あなたは簡単に続いことなく、アプリケーション内で使用できるPOJOにマッピング、あなたはネイティブSQLクエリを使用できるようにする必要があり

Query query = entityManager.createNativeQuery( 
       "SELECT a.col1 as col1, a.col2 as col2 FROM Account a", 
       "Account.getWithTemporalAttributes"); 
List<AccountTemporalDetails> results = query.getResultList(); 

@SqlResultSetMapping(
    name = "Account.getWithTemporalAttributes", 
    classes = { 
    @ConstructorResult(
     targetClass = com.company.domain.AccountTemporalDetails.class, 
     columns = { 
     @ColumnResult(name = "col1"), 
     @ColumnResult(name = "col2") 
     }) 
    }) 

これを使用するには、次の操作を行いますボイラープレートを書く。 @ConstructorResultアノテーションは、JPQL SELECT NEWの構文を模倣するためのものです。だから、AccountTemporalDetailsに正しい型の引数を取るコンストラクタがあることを確認するだけでよいでしょう。