Spring用外键保存复合主键
Posted
技术标签:
【中文标题】Spring用外键保存复合主键【英文标题】:Spring save composite primary key with foreign keys 【发布时间】:2016-04-27 14:15:39 【问题描述】:我在创建具有复合主键的实体时遇到问题,并且该键也是外键。这是我的表格和关系tables schematics .当我想创建新闻实体时,我收到了带有 null create newsTranslation 的错误消息。 NewsTranslation 具有复合主键,外键引用新闻表。
这是我的代码:
新闻汇总
@AggregateRoot
@Entity
@Table(name = "news")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class NewsAggregate extends AuditingAggregateRoot implements Serializable
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "news_id")
private Long newsId;
@ManyToOne
@JoinColumn(name = "id")
private UserAggregate authorId;
@Column(name = "publish_time")
private ZonedDateTime publishTime;
@Column(name = "published", nullable = false)
private boolean published = false;
@ManyToMany
@JoinTable(
name = "tags_news",
joinColumns = @JoinColumn(name = "news_id", referencedColumnName = "news_id"),
inverseJoinColumns = @JoinColumn(name = "tag", referencedColumnName = "tag"))
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Tags> tags = new HashSet<Tags>();
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL,
orphanRemoval = true)
private List<NewsTranslation> newsTranslation;
public NewsAggregate(UserAggregate authorId, Set<Tags> tags, String langCode,
String title, String shortDescription, String longDescription)
this.authorId = authorId;
this.tags = tags;
newsTranslation.add(
new NewsTranslation(this, langCode, title, shortDescription, longDescription)
);
//Getters, equal, hashCode
新闻翻译
@Entity
@Table(name = "news_translation")
/*@IdClass(NewsLangId.class)*/
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class NewsTranslation implements Serializable
private static final long serialVersionUID = 7576921328990303444L;
@EmbeddedId
private NewsLangId newsLangId;
@Column(name = "title", length = TITLE_MAX_LENGTH, nullable = false)
private String title;
@Column(name = "short_description", length = SHORT_DESC_MAX_LENGTH, nullable = false)
private String shortDescription;
@Column(name = "long_description", nullable = false)
private String longDescription;
@ManyToOne
@JoinColumn(name = "news_id", insertable = false, updatable = false)
private NewsAggregate newsAggregate;
@ManyToOne
@JoinColumn(name = "lang_code", insertable = false, updatable = false)
private Languages languages;
public NewsTranslation()
protected NewsTranslation(NewsAggregate newsAggregate, String langCode,String title, String shortDescription, String longDescription)
System.out.println(">>>>>>>>>>>>>>>.. NewsTranslation constructor");
this.title = title;
this.shortDescription = shortDescription;
this.longDescription = longDescription;
this.newsAggregate = newsAggregate;
this.languages = new Languages();
this.newsLangId = new NewsLangId(this.newsAggregate.getId(), langCode);
System.out.println(">>>>>>>>> NewsTranslation : title = "+this.title+", shortDescription = "+this.shortDescription+
", longDescription = "+this.longDescription+", newsAggregate = "+this.newsAggregate +", languages = "+this.languages);
// getters, setters
标签
@Entity
@Table(name = "tags")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Tags implements Serializable
private static final long serialVersionUID = 2995101252921266446L;
@Id
@Column(name = "tag", length = TAG_MAX_LENGTH, unique = true)
private String tag;
public Tags()
private Tags(Builder builder)
this.tag = Preconditions.checkNotNull(builder.tag);
public void setTag(String tag)
this.tag = tag;
NewsLangId
@Embeddable
public class NewsLangId implements Serializable
private static final long serialVersionUID = -4822628791720244835L;
@Column(name = "news_id")
private long newsId;
@Column(name = "lang_code")
private String langCode;
public NewsLangId()
public NewsLangId(long newsId, String langCode)
System.out.println("Create NewsLangId: "+newsId+", "+langCode);
this.newsId = newsId;
this.langCode = langCode;
// getters, setters, equal, hashcode
在 NewsFactory 中,我想使用 NewsTranlation 创建 NewsAggregate,但我有错误消息 NullPointer。
新闻工厂
Set<Tags> tagsSet = new HashSet<Tags>(tagsRepository.findAll());
UserAggregate login = userRepository.findOneByLogin("admin").get();
NewsAggregate news = new NewsAggregate(login,tagsSet, createNewsDto.getLangCode(), createNewsDto.getTitle(),
createNewsDto.getShortDescription(),createNewsDto.getLongDescription());
log.info(">>>>>>>>>>>> NewsFactory: newsAggregate = "+news);
return news;
错误:
java.lang.NullPointerException: null
at it.seiton.aexea.domain.model.news.NewsTranslation.<init>(NewsTranslation.java:55)
at it.seiton.aexea.domain.model.news.NewsAggregate.<init>(NewsAggregate.java:61)
at it.seiton.aexea.domain.model.news.NewsFactory.createNews(NewsFactory.java:55)
at it.seiton.aexea.domain.service.impl.NewsServiceDefault.createNews(NewsServiceDefault.java:29)
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.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
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.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208)
at com.sun.proxy.$Proxy184.createNews(Unknown Source)
at it.seiton.aexea.web.rest.NewsResource.createNews(NewsResource.java:43)
at it.seiton.aexea.web.rest.NewsResource$$FastClassBySpringC530334.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85)
at it.seiton.aexea.aop.logging.LoggingAspect.logAround(LoggingAspect.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.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:620)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:609)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:68)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:59)
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.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655)
at it.seiton.aexea.web.rest.NewsResource$$EnhancerBySpringCGLIB$$c9591bb7.createNews(<generated>)
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.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:817)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:731)
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:968)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:870)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:844)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:85)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
at com.codahale.metrics.servlet.AbstractInstrumentedFilter.doFilter(AbstractInstrumentedFilter.java:104)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at com.hazelcast.web.WebFilter.doFilter(WebFilter.java:360)
at io.undertow..core.ManagedFilter.doFilter(ManagedFilter.java:60)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration$ApplicationContextHeaderFilter.doFilterInternal(EndpointWebMvcAutoConfiguration.java:237)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:92)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:112)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:207)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
at org.springframework.web.filter.OncePerRequestFilter.doOncePerRequestFilter.java:107)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:87)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:131)
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.security.handlers.AbstractConfiityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.SessionRestoringHandler.handleRequest(SessionRestoringHandler.java:119)
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:284)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:263)
at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81)
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:174)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:202)
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:793)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
PS。对不起我的英语。
【问题讨论】:
你能粘贴你的标签实体吗? NewsTranslation 中的第 55 行是什么? @cralfaro 我添加标签实体。 @Alan NewsTranslation 中的第 55 行是this.newsLangId = new NewsLangId(this.newsAggregate.getId(), langCode);
。我认为当我创建 NewsAggregate 对象时,我正在获取 id 并且可以将其用于embeddedid,但这是行不通的。
【参考方案1】:
我通过更改生成的主键解决了我的问题。现在 java 生成 id,而不是 postgresql。
新闻汇总
@AggregateRoot
@Entity
@Table(name = "news")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class NewsAggregate extends AuditingAggregateRoot implements Serializable
private static final Logger log = LoggerFactory.getLogger(NewsAggregate.class);
@Id
@Column(name = "news_id")
private String newsId;
@ManyToOne
@JoinColumn(name = "author_id", referencedColumnName = "id")
private UserAggregate authorId;
@Column(name = "publish_date")
private ZonedDateTime publishTime = null;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(
name = "tags_news",
joinColumns = @JoinColumn(name = "news_id", referencedColumnName = "news_id"),
inverseJoinColumns = @JoinColumn(name = "tag", referencedColumnName = "tag"))
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Tags> tags = new HashSet<Tags>();
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "news_id", referencedColumnName = "news_id")
@Fetch(FetchMode.JOIN)
private List<NewsTranslation> newsTranslation = new ArrayList<NewsTranslation>();
public NewsAggregate(Set<Tags> tags, UserAggregate authorId)
this.newsId = generateId(authorId.getId());
this.tags = tags;
this.authorId = authorId;
this.publishTime = ZonedDateTime.now();
private NewsAggregate(Builder builder)
this.authorId = Preconditions.checkNotNull(builder.authorId);
this.publishTime = builder.publishTime;
this.tags = Preconditions.checkNotNull(builder.tags);
this.newsTranslation = Preconditions.checkNotNull(builder.newsTranslation);
private String generateId(long userId)
return ZonedDateTime.now().toInstant().toEpochMilli() + "_" + userId;
public static NewsAggregate createNews(Set<Tags> tags, UserAggregate authorId, CreateNewsDto createNewsDto)
NewsAggregate news = new NewsAggregate(tags, authorId);
log.info(">>>>>>>>>>>>>>>>>> news_id = "+news.getNewsId());
NewsLangId newsLangId = new NewsLangId(news.getNewsId(), "en");
NewsTranslation newsTranslation = new NewsTranslation(newsLangId, createNewsDto.getTitle(),
createNewsDto.getShortDescription(), createNewsDto.getLongDescription());
List<NewsTranslation> newsTranslations = new ArrayList<>();
newsTranslations.add(newsTranslation);
news.addTranslation(newsTranslations);
return news;
private void addTranslation(List<NewsTranslation> newsTranslations)
this.newsTranslation = newsTranslations;
感谢大家的有趣。我希望这会有所帮助。
【讨论】:
以上是关于Spring用外键保存复合主键的主要内容,如果未能解决你的问题,请参考以下文章
Doctrine ORM:使用由外键组成的复合主键持久化集合