2017-07-04 13 views
0

Spring BootとJPAの魔法を理解しようとしています。JPAとスプリングブートを使用したエンティティタイプ(ディスクリミネータ)の問い合わせ

ベースAssetから継承Assetクラス(また、私の場合は抽象的かもしれない) クラスModel:私は、次のクラスがあります。

// ASSET CLASS 

import javax.persistence.DiscriminatorColumn; 
import javax.persistence.DiscriminatorType; 
import javax.persistence.DiscriminatorValue; 
import javax.persistence.Entity; 
import javax.persistence.GeneratedValue; 
import javax.persistence.GenerationType; 
import javax.persistence.Id; 
import javax.persistence.Inheritance; 
import javax.persistence.InheritanceType; 

@Entity 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING) 
@DiscriminatorValue(value = "asset") 
public class Asset { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private long id; 
    private String name; 

    public long getId() { 
     return id; 
    } 

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

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 
} 

私のモデルクラスです。

// MODEL CLASS 

import javax.persistence.DiscriminatorValue; 
import javax.persistence.Entity; 


@Entity 
@DiscriminatorValue(value = "model") 
public class Model extends Asset { 

    private long version; 

    public long getVersion() { return version; } 

    public void setVersion(long version) { this.version = version; } 
} 

私はfindAllAssetsByType()を照会したいリポジトリを作成したが、私は完全に間違って何かをするようです。

// TEST REPOSITORY 
import static org.assertj.core.api.Assertions.assertThat; 

import assetservice.core.AppLogger; 
import assetservice.dao.AssetRepository; 
import java.util.ArrayList; 
import java.util.List; 
import org.apache.logging.log4j.Logger; 
import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; 
import org.springframework.test.context.junit4.SpringRunner; 

@RunWith(SpringRunner.class) 
@DataJpaTest 
public class TestAsset { 

    private static final Logger logger = AppLogger.getLogger(); 

    @Autowired 
    private AssetRepository ar; 

    @Test 
    public void doSomething1() { 
     Asset expected = new Asset(); 
     expected.setName("MyTestAsset"); 
     ar.save(expected); 
     Asset actual = this.ar.findOne(expected.getId()); 
     assertThat(actual).isEqualTo(expected); 
    } 

    @Test 
    public void doSomething2() { 
     Asset expected = new Model(); 
     expected.setName("MyTestModel"); 
     ar.save(expected); 
     Asset actual = this.ar.findOne(expected.getId()); 
     assertThat(actual).isEqualTo(expected); 
    } 

    @Test 
    public void doSomething3() { 
     Asset expectedModel = new Model(); 
     Asset expectedAsset = new Asset(); 
     expectedModel.setName("MyTestModel"); 
     expectedAsset.setName("MyTestAsset"); 
     ar.save(expectedModel); 
     ar.save(expectedAsset); 
     Asset actualModel = this.ar.findOne(expectedModel.getId()); 
     assertThat(actualModel).isEqualTo(expectedModel); 

     Asset actualAsset = this.ar.findOne(expectedAsset.getId()); 
     assertThat(actualAsset).isEqualTo(actualAsset); 

     List<Asset> expectedAssetList = new ArrayList<>(); 
     expectedAssetList.add(this.ar.findOne(expectedModel.getId())); 
     List<Asset> actualAssetList = this.ar.findAssetsByType("model"); 

     logger.info("\n\n\n\n\n\n\n\n"); 
     logger.info(expectedAssetList); 
     logger.info(actualAssetList); 
     logger.info("\n\n\n\n\n\n\n\n"); 
    } 
} 

テストdoSomething1doSomething2仕事を期待通り: は、ここで私はまた、私が何をしたいのか説明するために、少しテストを書いたAssetRepositoryインタフェース

//ASSET REPOSITORY 

import assetservice.entity.Asset; 
import java.util.List; 
import org.springframework.data.jpa.repository.JpaRepository; 

public interface AssetRepository extends JpaRepository<Asset, Long> { 

    //big problem - store specific - if discriminiator changes this has to change too... 
    //@Query("select a from Asset a where type = ?1") 
    List<Asset> findAssetsByType(String type); 
} 

です。テストdoSomething3は、原因Caused by: org.springframework.data.mapping.PropertyReferenceException: No property type found for type Asset!の失敗のようです

Failed to load ApplicationContext 
java.lang.IllegalStateException: Failed to load ApplicationContext 
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124) 
    at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83) 
    at org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener.prepareTestInstance(SpringBootDependencyInjectionTestExecutionListener.java:47) 
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:228) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:287) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:289) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) 
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191) 
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:114) 
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:57) 
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:66) 
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:498) 
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35) 
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24) 
    at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32) 
    at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93) 
    at com.sun.proxy.$Proxy1.processTestClass(Unknown Source) 
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:109) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:498) 
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35) 
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24) 
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:146) 
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:128) 
    at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404) 
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63) 
    at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:46) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 
    at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55) 
    at java.lang.Thread.run(Thread.java:748) 
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'assetRepository': Invocation of init method failed; nested exception is org.springframework.data.mapping.PropertyReferenceException: No property type found for type Asset! 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1628) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) 
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) 
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:742) 
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) 
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) 
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693) 
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360) 
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) 
    at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:120) 
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98) 
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116) 
    ... 47 more 
Caused by: org.springframework.data.mapping.PropertyReferenceException: No property type found for type Asset! 
    at org.springframework.data.mapping.PropertyPath.<init>(PropertyPath.java:77) 
    at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:329) 
    at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:309) 
    at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:272) 
    at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:243) 
    at org.springframework.data.repository.query.parser.Part.<init>(Part.java:76) 
    at org.springframework.data.repository.query.parser.PartTree$OrPart.<init>(PartTree.java:247) 
    at org.springframework.data.repository.query.parser.PartTree$Predicate.buildTree(PartTree.java:398) 
    at org.springframework.data.repository.query.parser.PartTree$Predicate.<init>(PartTree.java:378) 
    at org.springframework.data.repository.query.parser.PartTree.<init>(PartTree.java:89) 
    at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.<init>(PartTreeJpaQuery.java:64) 
    at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:103) 
    at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:214) 
    at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:77) 
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.<init>(RepositoryFactorySupport.java:436) 
    at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:221) 
    at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.initAndReturn(RepositoryFactoryBeanSupport.java:277) 
    at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:263) 
    at org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:101) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1687) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1624) 
    ... 62 more 

で失敗します。

私の質問は、この場合はカスタムクエリまたはquerydslを取りますか?ご覧のとおり、すでに@Query("select a from Asset a where type = ?1")で作業していますが、それは自動的にSpring Bootsを使用していません...もっと多くの資産タイプがあると言えますが、特定のタイプのクエリは非常に面倒です。私は照会するEntityManagerを使うべき

@Autowire 
private AssetRepository ar; 

... 
List<Model> models = ar.findAllByType("models"); 

:ような私がやりたいクエリごとに適切なエンティティタイプ:

@Autowire 
private ModelRepository mr; 

... 
List<Model> models = mr.findAll(); 

それはこのような何かはるかに簡単藤堂でしょうか? @Queryよりも良い方法がありますか?私は "資産"テーブルを作成し、すべてのエンティティを定義するのではなく、 "タイプ"のような列を使用するだけですか?

答えて

1

あなたの資産クラスには、列タイプは含まれていません。 このように、あなたのクラスは、これはあなたの問題を修正した場合、私に教えてください。この

@Id 
@GeneratedValue(strategy = GenerationType.AUTO) 
private long id; 
private String name; 
private String type; 

public long getId() { 
    return id; 
} 

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

public String getName() { 
    return name; 
} 

public void setName(String name) { 
    this.name = name; 
} 

public String getType() { 
    return type; 
} 

public void setType(String type) { 
    this.type = type; 
} 

ようになるはずです。

+0

です。追加されたのは @Column(insertable = false、updatable = false) プライベートString型。 しかし、それは良い練習ですか?あなたは私の他の質問についてどう思いますか:すべてのエンティティを定義するのではなく、 "資産"テーブルを作成し、 "タイプ"のような列を使用するだけですか? – maiksensi

+0

すべてのタイプに異なるクラスを用意したい場合(ビジネスニーズに都合がよい場合)。同時に、エンティティアセットに列タイプを設定することができ、アセットを拡張するすべてのエンティティを定義することができます。今すぐList models = ar.findAllByType( "models");を定義します。返されるリストは実際にモデルのリストになります。異なる資産タイプごとにmr.findAll()を呼び出す必要はありません。リスト models = ar.findAllByType( "models");実際にモデルを返しますリストモデル= ar。findAllByType( "test1");それはtest1などを返す –

+0

素敵な、答えのおかげで。 – maiksensi

関連する問題