C'est une application à ressort (pas de botte à ressort).
La base de données que j'utilise est MySQL.
Le problème que je rencontre est lors de l'enregistrement de l'entité Driver
qui a une relation plusieurs à un à la fois sur Carrier
et Location
.
Ce que je veux faire, c'est quand je fais la sauvegarde sur Driver. Le pilote ainsi que l'emplacement et le transporteur sont conservés dans la base de données. Le problème que j'ai, c'est quand j'essaie de sauver. J'obtiens une violation de clé en double
Trace de pile:
repository.saveAll(drivers);
Classes d'entité / modèle: (ont supprimé les getters / setters)
@Repository public interface DriverRepository extends JpaRepository<Driver, Long> { }
Code préparant les entités
@Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory() { LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); em.setDataSource(dataSource()); em.setPackagesToScan(new String[] { "greyhound" }); JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); em.setJpaVendorAdapter(vendorAdapter); em.setJpaProperties(additionalProperties()); return em; } @Bean public DataSource dataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://localhost:3306/greyhound1"); dataSource.setUsername("root"); dataSource.setPassword(""); return dataSource; } @Bean public PlatformTransactionManager transactionManager(EntityManagerFactory emf) { JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory(emf); return transactionManager; } @Bean public PersistenceExceptionTranslationPostProcessor exceptionTranslation() { return new PersistenceExceptionTranslationPostProcessor(); } Properties additionalProperties() { Properties properties = new Properties(); properties.setProperty("hibernate.hbm2ddl.auto", "create-drop"); properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect"); return properties; }
Question: est est-il possible de réaliser ce que j'essaie de faire? Attendez-vous à ce que hibernate gère les relations lorsque j'essaie d'enregistrer et d'associer un emplacement
à un pilote
s'il a déjà été enregistré au lieu d'essayer de l'enregistrer à nouveau.
Sinon, quelle est l’approche suggérée pour enregistrer ces entités?
Configuration de la source de données
private List<Driver> prepareEntityList(Result result) { List<Driver> drivers = new ArrayList<Driver>(); for(DriverAssignment driverAssignment : result.getDriverAssignments()) { Location location = new Location(); location.setLocationName(driverAssignment.getHomeLocation3()); location.setLocationId(driverAssignment.getHomeLocation()); Carrier carrier = new Carrier(); carrier.setCarrierName(driverAssignment.getCarrierId()); Driver driver = new Driver(); driver.setDriverId(driverAssignment.getDriverId()); driver.setFirstName(driverAssignment.getFirstName()); driver.setLastName(driverAssignment.getLastName()); driver.setMiddleInitial(driverAssignment.getMiddleInitial()); driver.setCarrier(carrier); driver.setLocation(location); drivers.add(driver); } return drivers; }
Mise à jour n ° 2
Avoir un DriverRepository comme celui-ci
@Entity @Table(name = "Driver") public class Driver { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Version @Column(name = "version") private int version; @Column(name = "driver_id") private Long driverId; @Column(name = "first_name") private String firstName; @Column(name = "last_name") private String lastName; @Column(name = "middle_init") private String middleInitial; @ManyToOne(fetch = FetchType.EAGER) @Cascade({CascadeType.ALL}) private Carrier carrier; @ManyToOne(fetch = FetchType.EAGER) @Cascade({CascadeType.ALL}) private Location location; @Entity @Table(name="Carrier") public class Carrier { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Version @Column(name = "version") private int version; @PrimaryKeyJoinColumn @Column(name = "carrier_name") private String carrierName; @OneToMany @JoinColumn(name = "carrier_id", referencedColumnName = "id") @Entity @Table(name="Locations") public class Location { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private Long id; @Version private Long version; @Column(name = "location_id") private Long locationId; @Column(name = "location_name") private String locationName; @OneToMany @JoinColumn(name = "location_id", referencedColumnName = "location_id") private List<Driver> drivers = new ArrayList<Driver>(); }
Pour enregistrer:
org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions WARN: SQL Error: 1062, SQLState: 23000 Feb 18, 2019 1:25:42 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions ERROR: Duplicate entry '910327' for key 'UK_lheij6i9eldhfhyu9j1q5fjls' Exception in thread "main" org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [UK_lheij6i9eldhfhyu9j1q5fjls]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:296) at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:253) at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:527) at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61) at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242) at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:135) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) at com.sun.proxy.$Proxy47.saveAll(Unknown Source) at greyhound.service.GreyhoundServiceImpl.process(GreyhoundServiceImpl.java:38) at greyhound.Main.main(Main.java:17) Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:59) at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42) at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113) at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99) at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:178) at org.hibernate.dialect.identity.GetGeneratedKeysDelegate.executeAndExtract(GetGeneratedKeysDelegate.java:57) at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:42) at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3073) at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3666) at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:81) at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:645) at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:282) at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:263) at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:317) at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:332) at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:289) at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:196) at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:127) at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:192) at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:135) at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:828) at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:795) at org.hibernate.engine.spi.CascadingActions$7.cascade(CascadingActions.java:298) at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:490) at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:415) at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:216) at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:149) at org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:428) at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:266) at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:196) at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:127) at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:192) at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:135) at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:62) at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:804) at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:789) 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.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:308) at com.sun.proxy.$Proxy44.persist(Unknown Source) at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:489) at org.springframework.data.jpa.repository.support.SimpleJpaRepository.saveAll(SimpleJpaRepository.java:521) at org.springframework.data.jpa.repository.support.SimpleJpaRepository.saveAll(SimpleJpaRepository.java:73) 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.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:359) at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200) at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:644) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:608) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) ... 11 more Caused by: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '910327' for key 'UK_lheij6i9eldhfhyu9j1q5fjls' at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:117) at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97) at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122) at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:970) at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1109) at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1057) at com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1377) at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:1042) at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:175) ... 69 more Process finished with exit code 1
6 Réponses :
Vous devez également renseigner Carrier
et Location
avec le Driver
créé:
@Transactional public void process() {
cela a besoin à faire en raison du mappage bidirectionnel que vous avez utilisé ( @OneToMany
)
Mise à jour :
Utilisez la configuration en cascade JPA , pas Hibernate one:
@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL) private Carrier carrier; @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL) private Location location;
Mise à jour 2
Après avoir examiné de plus près votre projet, il semble qu'il vous manque un configuration transactionnelle sur:
for(DriverAssignment driverAssignment : result.getDriverAssignments()) { Location location = new Location(); Carrier carrier = new Carrier(); Driver driver = new Driver(); driver.setCarrier(carrier); driver.setLocation(location); // add this location.getDrivers().add(driver); carrier.getDrivers().add(driver); drivers.add(driver); }
à l'intérieur de cette méthode, vous effectuez de nombreuses opérations de référentiel, ce qui est bien car toutes les méthodes SimpleJpaRepository sont transactionnelles.
Le problème à mon avis est que toutes ces opérations ne sont pas exécutées dans le même contexte de transaction et de persistance. (chaque opération s'exécute dans sa propre petite transaction et après cela, toutes les entités sont détachées du contexte de persistance).
REMARQUE: vous devrez peut-être jouer un peu avec la configuration pour activer la configuration de l'annotation @Transactional.
Merci, j'ai mis à jour le code comme conseillé et je suis d'accord que cela devrait être là. Cependant, cela n'a pas corrigé l'erreur et j'obtiens toujours la même erreur.
J'ai mis à jour l'article avec mes configurations de source de données et de gestionnaire d'entités
ajoutez la sauvegarde réelle que vous déclenchez
Mise à jour du message
Mis à jour, pas de joie.
Une façon de résoudre ce problème serait de simplement charger tous les emplacements et transporteurs afin qu'avec un findById (), ils soient liés à votre session. Utilisez ces objets obtenus pour être définis sur vos nouveaux objets pilote. Cela devrait résoudre le problème.
for(DriverAssignment driverAssignment : result.getDriverAssignments()) { Location location; if (driverAssignment.getHomeLocation() != null) { location = locationRepo.findById(driverAssignment.getHomeLocation()); } else { location = new Location(); } location.setLocationName(driverAssignment.getHomeLocation3()); Carrier carrier; if (driverAssignment.getCarrierId() != null) { carrier = carrierRepo.findById(driverAssignment.getCarrierId()); } else { carrier = new Carrier(); } Driver driver; if (driverAssignment.getDriverId() != null) { driver = driverRepo.findById(driverAssignment.getCarrierId()); } else { driver = new Driver(); } driver.setDriverId(driverAssignment.getDriverId()); driver.setFirstName(driverAssignment.getFirstName()); driver.setLastName(driverAssignment.getLastName()); driver.setMiddleInitial(driverAssignment.getMiddleInitial()); driver.setCarrier(carrier); driver.setLocation(location); drivers.add(driver); }
Cela ressemblerait à quelque chose comme ça. Ceci est juste un exemple simple car je ne connais pas le contexte réel.
J'ai répondu à votre question dans les commentaires ci-dessus. Veuillez vous y référer.
Un problème de duplication se produit lorsqu'il va insérer des entrées pour les deux côtés. La solution est de marquer un côté comme "mappé par" l'autre.
alors utilisez dans la classe Carrier
:
@OneToMany(mappedBy="location") @JoinColumn(name = "location_id", referencedColumnName = "location_id") private List<Driver> drivers = new ArrayList<Driver>();
Et dans Lieu
Classe:
@OneToMany(mappedBy="carrier") @JoinColumn(name = "carrier_id", referencedColumnName = "id") private List<Driver> drivers = new ArrayList<Driver>();
Nous devons transmettre l'identifiant en tant que nom de colonne référencé. Mappez l'entité Location comme ci-dessous.
@OneToMany @JoinColumn(name = "location_id", referencedColumnName = "id") private List<Driver> drivers = new ArrayList<Driver>();
Étant donné que Location
et Carrier
sont versionnés et que vous ne définissez pas la version dans les instances que vous créez, Hibernate les considère probablement comme nouvelles et essaie de les insérer (sinon , s'ils avaient besoin d'être mis à jour, Hibernate ne saurait de toute façon pas quelles versions comparer car il manque dans les instances mises à jour).
Premièrement, vous devez:
Location
et Carrier
existantes à partir de db et mettez-les à jour si elles ne sont pas nouvelles (vous le savez en vérifiant si l'ID est défini); Deuxièmement, vous avez également deux choix avec vos mappages d'entités actuels (et l'objectif déclaré de laisser Hibernate enregistrer correctement le graphique entier):
entityManager.merge (pilote)
pour que tout soit correctement inséré ou mis à jour; Location
et Carrier
existantes et appelez repository.saveAll (drivers)
dans la même transaction, alors cela fonctionnerait, car les instances de pilote seraient persistantes et l'opération PERSIST
serait mise en cascade sur des instances d'emplacement et d'opérateur encore attachées. Il y a (beaucoup) d'autres possibilités en fonction des choix architecturaux et des conventions utilisées dans votre projet, c'est-à-dire que je ne cascaderais jamais TOUT d'un côté beaucoup
à un côté un
(un exemple une conséquence indésirable est la suppression), et dans la plupart des cas, je voudrais toujours enregistrer explicitement le côté one
séparément, mais c'est à vous de décider.
J'ai préparé la solution fonctionnelle : Cepr0 / greyhound-demo a >.
J'ai retravaillé "un peu" votre projet - je l'ai fait avec la base de données Spring-Boot, Lombok et H2, juste à des fins de démonstration et pour le simplifier. Donc, si je ne me trompe pas, la tâche est de transformer ' affectations ' (à partir du site Greyhound): en trois entités: ie Le principal problème de cette tâche est que lors de l'enregistrement de l'entité Le code final de la méthode Pour minimiser la taille des données dans la base de données et le nombre de sélections SQL J'ai transformé les entités initiales comme suit: Pilote Emplacement strong> Transporteur Comme vous pouvez le voir, j'ai utilisé des identifiants naturels pour Location et PS Notez que cette solution n'est pas optimale. IMO pour l'améliorer, vous pouvez diviser le processus principal en deux parties: la première persiste des MISE À JOUR Branche avec la solution optimale: Cepr0 / greyhound-demo: async_and_batch_insert En raison de la persistance asynchrone des emplacements et des transporteurs et avec l'insertion par lots, le traitement ne prend qu'environ 5 secondes. @Data
@NoArgsConstructor
@Entity
@Table(name = "carriers")
public class Carrier {
@Id private String carrierId;
public Carrier(final String carrierId) {
this.carrierId = carrierId;
}
}
Driver
, Location
et Carrier
strong > avec les relations: @Data
@NoArgsConstructor
@Entity
@Table(name = "locations")
@IdClass(Location.PK.class )
public class Location {
@Id private Long locationId;
@Id private String locationName;
public PK getId() {
return new PK(locationId, locationName);
}
public void setId(PK id) {
this.locationId = id.getLocationId();
this.locationName = id.getLocationName();
}
public Location(final Long locationId, final String locationName) {
this.locationId = locationId;
this.locationName = locationName;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class PK implements Serializable {
private Long locationId;
private String locationName;
}
}
Driver
a une relation 'plusieurs-à-un' avec Location
et Carrier
. Driver
, nous devons utiliser les entités déjà persistantes Location
et Carrier
, ou utiliser nouveaux . Donc, pour le résoudre, nous devons:
Lieu
et le Transporteur
associés. Location
et Carrier
ne sont pas trouvés, créez-en de nouveaux. Driver
et définissez le Location
et le Carrier
trouvés ou les nouveaux ayant été créés. Pilote
(et en cascade conserver Location
et Carrier
s’ils ne sont pas trouvés). li>
GreyhoundService.process()
:@Getter
@Setter
@ToString
@EqualsAndHashCode(of = "id")
@Entity
@Table(name = "drivers")
public class Driver implements Persistable<Long> {
@Id private Long id;
private String firstName;
private String lastName;
private String middleName;
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "carrierId", foreignKey = @ForeignKey(name = "drivers_carriers"))
private Carrier carrier;
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumns(
value = {@JoinColumn(name = "locationId"), @JoinColumn(name = "locationName")},
foreignKey = @ForeignKey(name = "drivers_locations")
)
private Location location;
@Override
public boolean isNew() {
return true;
}
}
@Transactional
public void process() {
client.getAssignments()
.stream()
.forEach(a -> {
log.debug("[d] Assignment: {}", a);
Driver driver = new Driver();
driver.setId(a.getDriverId());
driver.setFirstName(a.getFirstName());
driver.setLastName(a.getLastName());
driver.setMiddleName(a.getMiddleName());
driver.setLocation(
locationRepo.findById(new Location.PK(a.getLocationId(), a.getLocationName()))
.orElse(new Location(a.getLocationId(), a.getLocationName()))
);
driver.setCarrier(
carrierRepo.findById(a.getCarrierId().trim())
.orElse(new Carrier(a.getCarrierId().trim()))
);
driverRepo.saveAndFlush(driver);
log.debug("[d] Driver: {}", driver);
});
}
Location -1---*- Driver -*---1- Carrier
{
"results": [
{
"oper_nbr": 1,
"carrier_cd": "GLX ",
"last_name": "JOHN",
"first_name": "SMITH",
"middle_init": null,
"home_loc_6": 12345,
"home_loc_3": "NLX",
"oper_class": "T"
},
{
"oper_nbr": 2,
"carrier_cd": "GLX ",
"last_name": "JOHN",
"first_name": "DOE",
"middle_init": null,
"home_loc_6": 67890,
"home_loc_3": "NLX",
"oper_class": "T"
}
]
}
Carrier
(et un composite dans Carrier
). Cela a permis non seulement de réduire la taille des données, mais également de réduire le nombre de requêtes SQL supplémentaires qu'Hibernate effectue lors du stockage d'entités complexes. Lorsque les tables Location
et Carrier
sont remplies, Hibernate n'effectue pas de requêtes inutiles pour les trouver mais prend leurs données dans son propre cache (vous pouvez le voir dans le journal de l'application). Location
s et des Carrier
s distincts et la seconde persiste simplement Driver sans trouver les
Location
et Carrier
. Les deux parties fonctionnent avec insertion par lots .
Merci d'avoir pris le temps pour toutes les explications et une solution de travail.
@MukulGoel De rien! Vous pouvez également accepter ma réponse ..))
comment effectuez-vous la sauvegarde réelle?
@MaciejKowalski: avoir mis à jour le message avec le référentiel et enregistrer les détails
toutes les données sont de nouvelles données? Ou est-ce que certains de ces emplacements / transporteurs existent déjà avant d'appeler cette méthode?
Il existe deux cas d'utilisation: 1) Lors de la toute première exécution, tout est nouveau. 2) lors des courses ultérieures, les données entrantes peuvent changer (pilotes, emplacements, transporteurs) et doivent être mises à jour dans la base de données en conséquence. est-ce que cela clarifie ce que vous demandiez?
Cela fait. Je suppose que l'identifiant sera nul lorsqu'il s'agit d'un nouvel objet? (puisque l'identifiant est généré en fonction de vos entités)
@mahieus oui si l'objet est nouveau, l'id sera nul lors de sa génération.
J'ai mis à jour ma réponse. Il s'agit cependant d'une implémentation très simple, vous devrez peut-être ajouter des vérifications supplémentaires et une optimisation, mais cela devrait fonctionner
quand vous dites exécution suivante .. vous voulez dire une nouvelle transaction? Ou peut-être le même que lors de la première manche?
remplacer le code de hachage et la méthode equals dans l'emplacement et le transporteur n'inclut pas l'id cela peut résoudre votre problème.