【问题标题】:Accessing a relational database using spring jpa/vaadin使用 spring jpa/vaadin 访问关系数据库
【发布时间】:2021-01-29 21:52:50
【问题描述】:

我在 mysql 中有一个包含两个表的数据库设置:

stock_info

stock_price_data:

第一个表的主键设置为“Ticker”,第二个表的外键也引用第一个表的“Ticker”,表示一对多关系。

我正在尝试使用 spring 数据在 vaadin Web 应用程序中访问这些数据。我尝试使用从AbstractEntity 扩展的服务、存储库和两个实体从表中提取所有数据。但是,我在运行时收到以下错误:


org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'stockPriceRepository' defined in com.stockmachine.v2.backend.repository.StockPriceRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Cannot resolve reference to bean 'jpaMappingContext' while setting bean property 'mappingContext'; nested exception is ...

这显然与我对一对多关系的引用/映射有关,但经过一番谷歌搜索后,我仍然找不到解决方案。

这些是我的实体类:

package com.stockmachine.v2.backend.entity;

import javax.persistence.*;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;

@Entity
@Table (name="stock_info")
public class Stock extends AbstractEntity implements Cloneable {
    //@Id
    //private String Ticker;
    @ManyToOne
    @JoinColumn(name = "Ticker")
    //private StockPrice stockPrice;
    
    private String Region;

    private String Sector;
    
    private String Industry;
    
    private String Type;
    
    /*public String getTicker() {
        return Ticker;
    }
    public void setTicker(String ticker) {
        Ticker = ticker;
    }*/
    
    public String getRegion() {
        return Region;
    }
    public void setRegion(String region) {
        Region = region;
    }
    public String getSector() {
        return Sector;
    }
    public void setSector(String sector) {
        Sector = sector;
    }
    public String getIndustry() {
        return Industry;
    }
    public void setIndustry(String industry) {
        Industry = industry;
    }
    public String getType() {
        return Type;
    }
    public void setType(String type) {
        Type = type;
    }
    
    

}
package com.stockmachine.v2.backend.entity;
import javax.persistence.*;
import java.util.LinkedList;
import java.util.List;
@Entity
@Table(name="stock_price_data")
public class StockPrice extends AbstractEntity  {
    @OneToMany(targetEntity=Stock.class, mappedBy="stock", fetch=FetchType.LAZY, cascade=CascadeType.ALL)
    @JoinColumn(name="Ticker")
    
    
    private double Price;

    private double open_price;

    private double close_price;

    private double volume;
    
    private double relative_strength;
    
    private double ma30;
    
    private double ma7;
    
    private double ma365;
    
    private String date_time;
        
        

    public double getPrice() {
        return Price;
    }

    public void setPrice(double price) {
        Price = price;
    }

    public double getOpen_price() {
        return open_price;
    }

    public void setOpen_price(double open_price) {
        this.open_price = open_price;
    }

    public double getClose_price() {
        return close_price;
    }

    public void setClose_price(double close_price) {
        this.close_price = close_price;
    }

    public double getVolume() {
        return volume;
    }

    public void setVolume(double volume) {
        this.volume = volume;
    }

    public double getRelative_strength() {
        return relative_strength;
    }

    public void setRelative_strength(double relative_strength) {
        this.relative_strength = relative_strength;
    }

    public double getMa30() {
        return ma30;
    }

    public void setMa30(double ma30) {
        this.ma30 = ma30;
    }

    public double getMa7() {
        return ma7;
    }

    public void setMa7(double ma7) {
        this.ma7 = ma7;
    }

    public double getMa365() {
        return ma365;
    }

    public void setMa365(double ma365) {
        this.ma365 = ma365;
    }

    public String getDate_time() {
        return date_time;
    }

    public void setDate_time(String date_time) {
        this.date_time = date_time;
    }

        


        
        
}
package com.stockmachine.v2.backend.entity;

import java.io.Serializable;

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;

@MappedSuperclass
public abstract class AbstractEntity implements Serializable {
    
  @Id
  private String Ticker;

public String getTicker() {
   return Ticker;
  }

  public boolean isPersisted() {
    return Ticker != null;
  }

  @Override
  public int hashCode() {
    if (getTicker() != null) {
      return getTicker().hashCode();
    }
    return super.hashCode();
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    if (obj == null) {
      return false;
   }
    if (getClass() != obj.getClass()) {
      return false;
    }
    AbstractEntity other = (AbstractEntity) obj;
 if (getTicker() == null || other.getTicker() == null) {
      return false;
    }
    return getTicker().equals(other.getTicker());
  }
  
}

编辑


多亏了这些建议,我决定完全删除 Abstract 实体并更改了实体类,如下所示:
public class Stock implements Cloneable {
    @OneToMany(mappedBy="stock", fetch=FetchType.LAZY, 
cascade=CascadeType.ALL)
    @Id
    private List<StockPrice> Ticker;
    private String Price;
    ...
     
    public List<StockPrice> getTicker() {
        return Ticker;
    }
    public void setTicker(List<StockPrice> ticker) {
        Ticker = ticker;
    }

但我仍然遇到相同(或类似)的错误:


org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'stockRepository' defined in com.stockmachine.v2.backend.repository.StockRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Cannot resolve reference to bean 'jpaMappingContext' while setting bean property 'mappingContext'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaMappingContext': Invocation of init method failed; nested exception is org.hibernate.AnnotationException: No identifier specified for entity: com.stockmachine.v2.backend.entity.StockPrice
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:342) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:113) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1697) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1442) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:324) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:624) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:612) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.data.repository.config.DeferredRepositoryInitializationListener.onApplicationEvent(DeferredRepositoryInitializationListener.java:51) ~[spring-data-commons-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.data.repository.config.DeferredRepositoryInitializationListener.onApplicationEvent(DeferredRepositoryInitializationListener.java:36) ~[spring-data-commons-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:404) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:361) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:898) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:554) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:143) ~[spring-boot-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758) ~[spring-boot-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750) ~[spring-boot-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237) ~[spring-boot-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) ~[spring-boot-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at com.stockmachine.v2.Application.main(Application.java:14) ~[classes/:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:564) ~[na:na]
    at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) ~[spring-boot-devtools-2.3.2.RELEASE.jar:2.3.2.RELEASE]
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaMappingContext': Invocation of init method failed; nested exception is org.hibernate.AnnotationException: No identifier specified for entity: com.stockmachine.v2.backend.entity.StockPrice
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1794) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:594) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:324) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:330) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    ... 33 common frames omitted
Caused by: org.hibernate.AnnotationException: No identifier specified for entity: com.stockmachine.v2.backend.entity.StockPrice
    at org.hibernate.cfg.InheritanceState.determineDefaultAccessType(InheritanceState.java:266) ~[hibernate-core-5.4.18.Final.jar:5.4.18.Final]
    at org.hibernate.cfg.InheritanceState.getElementsToProcess(InheritanceState.java:211) ~[hibernate-core-5.4.18.Final.jar:5.4.18.Final]
    at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:781) ~[hibernate-core-5.4.18.Final.jar:5.4.18.Final]
    at org.hibernate.boot.model.source.internal.annotations.AnnotationMetadataSourceProcessorImpl.processEntityHierarchies(AnnotationMetadataSourceProcessorImpl.java:254) ~[hibernate-core-5.4.18.Final.jar:5.4.18.Final]
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess$1.processEntityHierarchies(MetadataBuildingProcess.java:230) ~[hibernate-core-5.4.18.Final.jar:5.4.18.Final]
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:273) ~[hibernate-core-5.4.18.Final.jar:5.4.18.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1224) ~[hibernate-core-5.4.18.Final.jar:5.4.18.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1255) ~[hibernate-core-5.4.18.Final.jar:5.4.18.Final]
    at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:58) ~[spring-orm-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365) ~[spring-orm-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:391) ~[spring-orm-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130) ~[na:na]
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630) ~[na:na]
    at java.base/java.lang.Thread.run(Thread.java:832) ~[na:na]

public class StockPrice  {
    @ManyToOne
    @JoinColumn(name = "Ticker")
    private StockPrice stockPrice;

    private List<Double> Price;
    ...

【问题讨论】:

    标签: mysql spring spring-boot hibernate jpa


    【解决方案1】:

    在您的 Stock 实体上,您应该将 Collection 映射到您的 StockPrice 实体,并且关系应该是双向的,例如:

    public class Stock extends AbstractEntity  {
    @OneToMany(mappedBy="stock", fetch=FetchType.LAZY, cascade=CascadeType.ALL)
    /*@JoinColumn(name = "Ticker") <- Don't use this, let hibernate figure this out by the 'mappedBy' */
    private List<StockPrice> Price;
    (...)
    

    public class StockPrice extends AbstractEntity {
    @ManyToOne
    @JoinColumn(name = "Ticker")
    private StockPrice stockPrice;
    

    但请记住,您的 StockPrice 不能只是扩展您的 AbstractEntity,因为它有一个复合键

    【讨论】:

    • 完全摆脱 AbstractEntity 会更好吗?或者也许从我的 sql 表中删除外键?
    • 如果您希望将这种关系作为 OneToMany,我想最好的方法是删除 AbstractEntity,因为它的唯一目的是定义一个不完全适用于其中一个的主键实体。但这只是个人喜好问题...尝试在您的 StockPrice 上添加一个不同的@Id,但仍然保留“ticker”列以供参考 Stock,这是您的游乐场 :)
    • 谢谢,也许是个愚蠢的问题,但是您将 Price 设置为 List&lt;StockPrice&gt;&lt;StockPrice&gt; 部分的意义是什么? StockPrice 显然是实体类,但这与我们的列表有何关系?对于每个代码值,有多个价格(以及所有其他参数的多个),如果变量名称与 SQL 列名称相同,这是否会自动将这些价格存储在基于变量名称的列表中?
    • 不,它不会,这就是为什么您需要另一个表列作为主键,而仅凭ticker 不足以满足您的需要,type 参数将告诉您的 ORM 将两者关联起来表格
    【解决方案2】:

    我相信该错误表明private double Price 需要是一个集合,因为它与 StockPrice 处于@OneToMany 关系。例如,您可以通过使用列表来解决此问题:

    private List<Double> Price;
    

    或一组:

    private Set<Double> Price;
    

    【讨论】:

    • 谢谢!这修复了其中一个错误,但我仍然收到以下信息:Caused by: org.hibernate.AnnotationException: Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn: com.stockmachine.v2.backend.entity.StockPrice.Price
    • 是的,这是您的代码的另一个问题。我建议查看本教程以了解如何实现映射:baeldung.com/hibernate-one-to-many
    猜你喜欢
    • 1970-01-01
    • 2021-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-08
    • 2011-03-13
    • 1970-01-01
    • 2017-03-13
    相关资源
    最近更新 更多