I'm trying to save a list of entity objects. Here is my method which is defined in a Service class:
#Transactional
public void creteEmployee(List<Employee> employeeList) {
employeeRepository.saveAll(employeeList);
}
And here is my JPA repository:
public interface EmployeeRepository extends PagingAndSortingRepository<Employee, Long> {
Page<Employee> findByCompany(Pageable pageable, Company company);
}
I've a unique constraint defined in my entity. If any item from the employeeList violates the unique constraint, I expect no one from the employeeList will be saved. Unfortunately all items except the problematic one is saved and also an DataIntegrityViolationException is raised. What should be done to make it atomic?
Related
I have a simple abstract DAO, and I have created the following method:
protected T update(T entity) {
return em.merge(entity);
}
where the entity is just any object annotated with #Entity in my application. Now... I want to throw an exception if you try to update a non existing object. I was going to perform a find before the merge, throwing an exception if the find operation returns null and merging if the entity exists. I was wandering if a better way exists for doing this.
A possible solution: You can do a check based on your primary key. An entity must (should?) have an #Id field:
#Entity
public class Entity implements EntityInterface{
#Id
private Long id;
#Override
public Long getId(){
return this.id;
}
}
with the interface
public interface EntityInterface{
public Long getId();
}
By default, when you instantiate your entity, id is null and a value is assigned only after persisting in the database: The id will be generated by the method you defined via #GeneratedValue. Consequently, the following check should meet your requirement:
public abstract class AbstractService<T extends EntityInterface>{
protected T update(T entity){
// if by any chance you have to call this method on an entity with a null
// primary key, it means that the entity has not been persisted in the
// database yet
if(entity.getId() == null){
// or whatever
return null;
}
return em.merge(entity);
}
}
Hope this help
Source: JB Nizet's comment and personal code
Is there a way to implement JPA Entity using Map? either extended HashMap or contain a hashmap i.e.:
#Entity
#Table(employee)
public class Employee {
/* .... */
void set(String columnName, Object columnValue) { /*...*/ }
Object get(String columnName) { /*...*/ }
}
and
#RepositoryRestResource
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}
this way, there is no need to provide model attributes in the Employee class. Basically, whatever columns are defined in the database, it will be a property like entry in the Employee class.
Employee emp;
...
emp.get("name");
emp.get("id");
Is something like this possible?
Though not possible in vanilla JPA, EclipseLink dynamic entities (https://wiki.eclipse.org/EclipseLink/Examples/JPA/Dynamic) might be what you want. It allows for working with entities in a map-like fashion. Not sure if it is sufficient for your use case, though.
I am using Spring Boot to implement rest api. There are three entities SeqTb, PairTb, and GroupTb and they are nested. SeqTb has manytoone with PairTb. PairTb has onetomany relationship with SeqTb and also manytoone with GroupTb.
//SeqTb.java
#Entity
#Table(name="SEQ_TB")
public class SeqTb implements Serializable {
.......
#ManyToOne
#JoinColumn(name="PAIR_ID")
private PairTb pairTb;
......
}
// PairTb.java
#Entity
#Table(name="PAIR_TB")
#NamedQuery(name="PairTb.findAll", query="SELECT p FROM PairTb p")
public class PairTb implements Serializable {
#ManyToOne
#JoinColumn(name="GROUP_ID")
private GroupTb groupTb;
#OneToMany(mappedBy="pairTb", cascade=CascadeType.ALL)
private List<SeqTb> seqTbs;
}
//GroupId.java
#Entity
#Table(name="GROUP_TB")
public class GroupTb implements Serializable {
//bi-directional many-to-one association to PairTb
#OneToMany(mappedBy="groupTb", cascade=CascadeType.ALL)
private List<PairTb> pairTbs;
}
In my controller GET request with analysisId was handled in the following way:
#RequestMapping(
value = "/api/seqs/{analysis_id}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<SeqTb> getSeqByAnalysisId(#PathVariable("analysis_id") String analysis_id) {
SeqTb seq = seqService.findByAnalysisId(analysis_id);
return new ResponseEntity(seq, HttpStatus.OK);
}
I also create a bean class SeqServiceBean that extends the interface SeqService which in turn calls methods from the following JPA repository for query.
//SeqRepository.java
#Repository
public interface SeqRepository extends JpaRepository<SeqTb, Integer> {
#Override
public List<SeqTb> findAll();
public List<SeqTb> findByAnalysisId(String analysisId);
}
When I query a SeqTb object with SeqTb.PairTb == null, the api works just fine. However, if the analysisId I put in the url belongs to a SeqTb record that associates with a pairId which in turn belongs to a groupId, the program would go nuts. Below is the output, the first part output is correct (bold text). After that it keeps printing PairTb and GroupTb in loops (repeating keywords pairTb, groupTb).
{"rowId":8,"analysisId":"cce8d2c2-a6dc-4ee9-ba97-768f058abb50","analyteCode":"D","center":"UCSC",
"pairTb":{"rowId":4,"pairCode":"01ad975d-c2ed-4e4d-bd3b-c9512fc9073c","groupTb":{"rowId":1,"groupName":"PAWG_pilot-50","pairTbs":[{"rowId":1,"pairCode":"00ad0ffe-2105-4829-a495-1c2aceb5bb31","groupTb":{"rowId":1,"groupName":"PAWG_pilot-50","pairTbs":
Meanwhile I got lots of errors from tomcat server:
Caused by: java.lang.IllegalStateException: getOutputStream() has already been called for this response
at org.apache.catalina.connector.Response.getWriter(Response.java:565) ~[tomcat-embed-core-8.0.32.jar:8.0.32]
at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:212) ~[tomcat-embed-core-8.0.32.jar:8.0.32]
How do I ignore the nested entity object inside an entity and get only the meaning columns?
You can also annotate a property with #JsonIgnore in order to not output that field.
Found the solution. Created a value object that only contains the specific columns from entity and leave out the nested entity object. And it works.
I am trying to create a query in Spring-data-jpa to find a Person entity by Address's id. Person have OneToOne relationship with Address and both have id as primary key.
public abstract class AbstractEntity{
#Id
Long id;
}
public class Person extends AbstractEntity {
#OneToOne
Address address;
}
public class Address extends AbstractEntity {
}
public interface PersonRepository implements JpaRepository<Person, Long> {
Person findByAddressId(Long addressId); // Throws cannot create metamodel exception
Person findByAddress_Id(Long addressId); // Throws cannot create metamodel exception
}
I'm thinking that the method name findByAddressId and findByAddress_Id are ambiguous for Spring data jpa query look-up strategies as both Person and Address entities have id as their attributes.
Is it possible to write query in Spring-data-jpa to find parent entity by child attribute where parent and child both have same attribute, without writing SQL?
I am using EF CF approach for a website with MySQL.
For some reason EF creates a column in my Post table called "Discriminator" and contains the VARCHAR "Post".
Why is this column created? Can I do something to avoid it being created? Are there any advantages of having this column?
The Discriminator column is used and required in Table-Per-Hierarchy inheritance scenarios. If you for example have a model like this ...
public abstract class BaseEntity
{
public int Id { get; set; }
//...
}
public class Post : BaseEntity
{
//...
}
public class OtherEntity : BaseEntity
{
//...
}
... and make the BaseEntity part of the model, for instance by adding a DbSet<BaseEntity> to your derived context, Entity Framework will map this class hierarchy by default into a single table, but introduce a special column - the Discriminator - to distinguish between the different types (Post or OtherEntity) stored in this table. This column gets populated with the name of the type (again Post or OtherEntity).
You can stop the column being created by adding the [NotMapped] data annotation to the models that are inheriting from your base class. This will tell EF not to add your class to future migrations, removing the discriminator column.
public class BaseClass
{
}
[NotMapped]
public class InheritingClass : BaseClass
{
}
For completeness, if you want to use the fluent API to stop the inheriting class from being mapped with entity (and therefore stopping the discriminator column being created) you can do the following:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Ignore<InheritingClass>();
}