21500


多対多である  
Entity A → 中間テーブル Z → Entity C

また、1対1である  
Entity B → Entity C

という構造を、Spring Data JPAで実装したとき、

Entity A

[code]

    @Entity
    @Table(name="a")
    public class A {
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        @Column(name="id", nullable=false)
        private long id;
    
        @Column(name="unique_id", nullable=false)
        private String uniqueId;
    
        @OneToMany(fetch=FetchType.EAGER, mappedBy="a", targetEntity=Z.class)
        private List<Z> z;
    
        getter and setter
    }
    
[/code]

Entity B

[code]

    @Entity
    @Table(name="b")
    public class B {
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        @Column(name="id", nullable=false)
        private long id;
    
        @Column(name="c_unique_id", nullable=false)
        private String cUniqueId;
    
        @OneToOne
        @JoinColumn(name="c_unique_id", referencedColumnName="unique_id", insertable=false, updatable=false)
        private C c;
    
        getter and setter
    }
    
[/code]

Entity Z

[code]

    @Entity
    @Table(name="z")
    public class Z {
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        @Column(name="id", nullable=false)
        private long id;
    
        @Column(name="a_unique_id", nullable=false)
        private String aUniqueId;
    
        @Column(name="c_unique_id", nullable=false)
        private String cUniqueId;
    
        @ManyToOne
        @JoinColumn(name="a_unique_id", referencedColumnName="unique_id", insertable=false, updatable=false)
        private A a;
    
        @ManyToOne
        @JoinColumn(name="c_unique_id", referencedColumnName="unique_id", insertable=false, updatable=false)
        private C c;
    
        getter and setter
    }
    
[/code]

Entity C

[code]

    @Entity
    @Table(name="c")
    public class C {
    
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        @Column(name="id", nullable=false)
        private long id;
    
        @Column(name="unique_id", nullable=false)
        private String uniqueId;
    
        @OneToMany(fetch=FetchType.EAGER, mappedBy="c", targetEntity=Z.class)
        private List<Z> z;
    
        @OneToOne(fetch=FetchType.EAGER, mappedBy="c", targetEntity=B.class)
        private B b;
    }
    
[/code]

となりますが、  
A,Bのselect時は問題ないのですが、Cをセレクトしたときにエラーが発生します。

[code]

    @Query("select c from C c where c.deleteTs is not null")
    List<C> findDeleted(Pageable pageable);
    
[/code]

[code]

    java.lang.IllegalArgumentException: Can not set java.lang.String field package.c.uniqueId to java.lang.Long
        at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(Unknown Source)
        at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(Unknown Source)
        at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(Unknown Source)
        at sun.reflect.UnsafeObjectFieldAccessorImpl.get(Unknown Source)
        at java.lang.reflect.Field.get(Unknown Source)
        at org.hibernate.property.DirectPropertyAccessor$DirectGetter.get(DirectPropertyAccessor.java:57)
        at org.hibernate.tuple.component.AbstractComponentTuplizer.getPropertyValue(AbstractComponentTuplizer.java:76)
        at org.hibernate.tuple.component.AbstractComponentTuplizer.getPropertyValues(AbstractComponentTuplizer.java:82)
        at org.hibernate.tuple.component.PojoComponentTuplizer.getPropertyValues(PojoComponentTuplizer.java:107)
        at org.hibernate.type.ComponentType.getPropertyValues(ComponentType.java:435)
        at org.hibernate.type.ComponentType.getHashCode(ComponentType.java:259)
        at org.hibernate.engine.spi.EntityUniqueKey.generateHashCode(EntityUniqueKey.java:84)
        at org.hibernate.engine.spi.EntityUniqueKey.(EntityUniqueKey.java:65)
        at org.hibernate.type.EntityType.loadByUniqueKey(EntityType.java:712)
        at org.hibernate.type.EntityType.resolve(EntityType.java:492)
        at org.hibernate.engine.internal.TwoPhaseLoad.doInitializeEntity(TwoPhaseLoad.java:170)
        at org.hibernate.engine.internal.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:144)
        at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:1114)
        at org.hibernate.loader.Loader.processResultSet(Loader.java:972)
        at org.hibernate.loader.Loader.doQuery(Loader.java:920)
        at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:354)
        at org.hibernate.loader.Loader.doList(Loader.java:2551)
        at org.hibernate.loader.Loader.doList(Loader.java:2537)
        at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2367)
        at org.hibernate.loader.Loader.list(Loader.java:2362)
        at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:496)
        at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:387)
        at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:229)
        at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1260)
        at org.hibernate.internal.QueryImpl.list(QueryImpl.java:103)
        at org.hibernate.jpa.internal.QueryImpl.list(QueryImpl.java:573)
        at org.hibernate.jpa.internal.QueryImpl.getResultList(QueryImpl.java:449)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.springframework.orm.jpa.SharedEntityManagerCreator$DeferredQueryInvocationHandler.invoke(SharedEntityManagerCreator.java:364)
        at com.sun.proxy.$Proxy163.getResultList(Unknown Source)
        at org.springframework.data.jpa.repository.query.JpaQueryExecution$CollectionExecution.doExecute(JpaQueryExecution.java:114)
        at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:78)
        at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:100)
        at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:91)
        at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:413)
        at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:391)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodIntercceptor.invoke(CrudMethodMetadataPostProcessor.java:122)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
        at com.sun.proxy.$Proxy57.findByUserIdAndDeleted(Unknown Source)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:201)
        at com.sun.proxy.$Proxy58.findByUserIdAndDeleted(Unknown Source)
        at package.ArticleController.findC(ArticleController.java:87)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:111)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:806)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:729)
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
        at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.springframework.web.multipart.support.MultipartFilter.doFilterInternal(MultipartFilter.java:118)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
        at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
        at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:673)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1526)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1482)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Unknown Source)
    
[/code]

unique_idフィールドにLongを入れようとしているようですがなぜでしょうか？

なお、Repositoryクラスの肥大化を懸念し、@Query()アノテーションでの結合を避けたく、  
また、N+1問題の回避のため、遅延fetchも考えていません。


CC BY-SA 3.0
2016-01-29T11:02:34.203
21474
2016-02-01T07:41:01.460
2016-01-30T04:39:02.963
2808
8396
question
spring java8 jpa
JPA/複数Entityに結合されるテーブルを単体でセレクトすることはできない？


JPAアノテーション的には、エンティティ`C`の

[code]

    @OneToOne(fetch=FetchType.EAGER, mappedBy="c", targetEntity=B.class)
    private B b;
    
[/code]

を利用してエンティティ`B`をfetchする際は、`B`エンティティがフィールド`c`(に対応するカラム`c_unique_id`)に持っている`C`の
**PK** (`@Id`アノテーションが付いているフィールド)をキーとして利用しようとします。  
イメージとしては次のようなSQLでしょうか。

[code]

    select * from B b inner join
    (select * from C where C.deleteTs is not null) c
    on ( b.c_unique_id = c.id);
    
[/code]

`c.id`は`Long`なのに`b.c_unique_id`はそうじゃない、というエラーですね。

以下にも同様の質問がありました。

  * [JPA OneToOne relatioship for a non primary key column - Stack Overflow](https://stackoverflow.com/questions/20041215/jpa-onetoone-relatioship-for-a-non-primary-key-column)

* * *

今回の場合なのですが、`C`の`id`が不要ですね。少なくとも`@Id`を付与する意味が無いです。  
`uniqueId`が名前の通りユニークでかつ`nullable=false`なのであれば、こちらに`@Id`を付けることで今回のクエリはJPA的には想定通り実行されると思います。

(ただ実際には、`id`フィールドを用意して`@Id`を付けているのはそれなりの理由があると思いますので、そちらとの兼ね合いも検討する必要があるかと。)


CC BY-SA 3.0
2016-01-30T05:19:56.233
21500
2016-01-30T05:19:56.233
2017-05-23T12:38:55.250
-1
2808
21474
answer


回答は yukihane さんのものが的を得ていたので承認させていただきましたが、  
一点、別解があったようなので記載させていただきます。

通常、select A の際、getterでCを取得、  
また、select C の際、getterでAを取得するシチュエーションがほとんどかと思いますが、  
単方向結合のみでよい場合、結合される側に@OneToOneなどのディメンションリレーションシップアノテーションおよび、@JoinColumnは不要なようです。

以下、質問内容の定義での例です。

Cをセレクト時はZ及びBの結合はしないものとします。

Class A

[code]

    @Entity
    @Table(name="a")
    public class A {
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        @Column(name="id", nullable=false)
        private long id;
    
        @Column(name="unique_id", nullable=false)
        private String uniqueId;
    
        @OneToMany(fetch=FetchType.EAGER, mappedBy="a", targetEntity=Z.class)
        private List<Z> z;
    
        getter and setter
    }
    
[/code]

Class Z

[code]

    @Entity
    @Table(name="z")
    public class Z {
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        @Column(name="id", nullable=false)
        private long id;
    
        @Column(name="a_unique_id", nullable=false)
        private String aUniqueId;
    
        @Column(name="c_unique_id", nullable=false)
        private String cUniqueId;
    
        @ManyToOne
        @JoinColumn(name="a_unique_id", referencedColumnName="unique_id", insertable=false, updatable=false)
        private A a;
    
        @ManyToOne
        @JoinColumn(name="c_unique_id", referencedColumnName="unique_id", insertable=false, updatable=false)
        private C c;
    
        getter and setter
    }
    
[/code]

CLass C

[code]

    @Entity
    @Table(name="c")
    public class C {
    
        private long id;
        private String uniqueId;
        private List<Z> z;
        private B b;
    }
    
[/code]

Class B

[code]

    @Entity
    @Table(name="b")
    public class B {
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        @Column(name="id", nullable=false)
        private long id;
    
        @Column(name="c_unique_id", nullable=false)
        private String cUniqueId;
    
        @OneToOne
        @JoinColumn(name="c_unique_id", referencedColumnName="unique_id", insertable=false, updatable=false)
        private C c;
    
        getter and setter
    }
    
[/code]


CC BY-SA 3.0
2016-02-01T07:41:01.460
21566
2016-02-01T07:41:01.460
8396
21474
answer