This my Product class that extends a BaseClass and I get error in
#JoinColumn(name = "fk_supplier",referencedColumnName = "supplier_id")
private Supplier supplier;
and error is 'Many To One' attribute type should not be 'Supplier'
#Table
#Data
public class Product extends BaseEntity {
#ManyToMany
private List<Customer> customers = new ArrayList<>();
#ManyToOne
#JoinColumn(name = "fk_supplier",referencedColumnName = "supplier_id")
private Supplier supplier;
}
And this is my Supplier Class
#Table
#Data
public class Supplier extends BaseEntity {
#Column
private boolean active;
#Column
private Date foundationDate;
//Enum type to String type in mysql
#Column
#Enumerated(EnumType.STRING)
private Type type;
#OneToMany(targetEntity = Product.class)
private List<Product> products = new ArrayList<>();
}
supplier_id column is defined under which entity?, means in the provided snippet for Supplier entity no such field is present.
I hope the base entity will only be having columns that are generic and applicable over every entity you will be using. So if you specify referencedColumnName be sure that it align with what you have in the definitions. By default it will the primary key of the referenced entity, here primary key of Supplier table.
Please try to do like this, it may solve the issue i think
#JoinColumn(name = "fk_supplier")
private Supplier supplier;
Related
I have a problem when mapping a List from a List.
All default fields of Entity are well mapped.
ex) (Entity)String date -> (DTO) String date
However, the Join object field exists in Entity.
We need to pull the data out of this object field and map it anew.
In the case of a single Entity to single DTO rather than a List to List, this was easily possible.
#Mapping(target = ".", source = "user")
This way we were able to map all fields of the user object field that the Entity has to the remaining unmapped fields.
However, trying the same on a List has no effect.
Which method should I use?
#Entity(name = "refund")
public class RefundEntity extends BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int refundId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id")
private UserEntity user;
private int refundAmount;
}
and
public class AdminRefundUserDto {
#AllArgsConstructor
#Getter
public static class Response {
private int refundAmount;
private String marketName;
private String bizNumber;
private String bizUserName;
}
}
and
#Entity(name = "user")
public class UserEntity extends BaseEntity {
#Id
#GeneratedValue(generator = "uuid4")
#GenericGenerator(name = "uuid", strategy = "uuid4")
#Column(columnDefinition = "BINARY(16)")
private UUID userId;
private String userName;
private String password;
private String phoneNumber;
private String marketName;
private String bizUserName;
private String bizNumber;
}
and I used
#Mapping(target = ".", source = "refundList.user")
List<AdminRefundUserDto.Response> toDtoList(List<RefundEntity> refundList);
First of all, create a method for the mapper with a SourceObject parameter that return a TargetObject
#Named("toResponseDto")
//add your mapping
AdminRefundUserDto.Response toResponseDto(RefundEntity refundEntity);
if you have complex logic of mapping, you can also create a custom method to map a certain target parameter: see Custom Mapper with MapStruct
Then add an IterableMapping
#IterableMapping(qualifiedByName = "toResponseDto")
List<AdminRefundUserDto.Response> toDtoList(List<RefundEntity> refundList);
I have a parent entity 'contracts' that has a one-to-one relation with another entity 'child-contract'. the interesting thing is that the mapping field ('contract_number')id not a primary key-foreign key but is rather a unique field in both the tables. Also it is possible for a contracts to not have any child contract altogether. With this configuration I have observed hibernate to generate 1 additional query every time a contracts does not have a child-contract. I filed this behavior very strange. Is there a way to stop these unnecessary query generation or have I got something wrong.
below is a piece of my code configuration.
#Data
#Entity
#Table(name = "contracts")
public class Contracts implements Serializable {
#Id
#JsonIgnore
#Column(name = "id")
private String id;
#JsonProperty("contract_number")
#Column(name = "contract_number")
private String contractNumber;
#OneToOne(fetch=FetchType.EAGER)
#Fetch(FetchMode.JOIN)
#JsonProperty("crm_contracts")
#JoinColumn(name = "contract_number", referencedColumnName = "contract_number")
private ChildContract childContract ;
}
#Data
#NoArgsConstructor
#Entity
#Table(name = "child_contract")
#BatchSize(size=1000)
public class ChildContract implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#JsonProperty("id")
#Column(name = "id")
private String id;
#JsonProperty("contract_number")
#Column(name = "contract_number")
private String contractNumber;
}
Please help.
Thank-you
You can use NamedEntityGraph to solve multiple query problem.
#NamedEntityGraph(name = "graph.Contracts.CRMContracts", attributeNodes = {
#NamedAttributeNode(value = "crmContract") })
Use this on your repository method as
#EntityGraph(value = "graph.Contracts.CRMContracts", type = EntityGraphType.FETCH)
// Your repo method in repository
Lets assume we have a complex JPA relation, a fraction of which looks like this:
#MappedSuperclass
public class DiffEntity {
private String diffId;
public DiffEntity() {
this.diffId = UUID.randomUUID().toString();
}
//...
}
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public class ParentEntity extends DiffEntity {
#Id
#GeneratedValue
private long id;
#Column
private String name;
//...
}
#Entity
public class Construct extends ParentEntity {
#Column
private String variable;
#OneToMany(mappedBy = "construct", cascade = CascadeType.ALL)
private List<Partconstruct> partconstructs;
//...
}
#Entity
public class Partconstruct extends ParentEntity {
#OneToMany(mappedBy = "partconstruct", cascade = CascadeType.ALL)
private List<Field> fields;
#OneToMany(mappedBy = "partconstruct", cascade = CascadeType.ALL)
private List<Hardparameter> hardparameters;
#ManyToOne
#JoinColumn(name = "construct_id")
private Construct construct;
//...
}
#Entity
public class Field extends ParentEntity {
#Column
private int fieldSize;
#ManyToOne
#JoinColumn(name = "partconstruct_id")
private Partconstruct partconstruct;
//...
}
#Entity
public class Hardparameter extends ParentEntity {
#Column
private String value;
#ManyToOne
#JoinColumn(name = "partConstruct_Id")
private Partconstruct partConstruct;
//...
}
We are concerned with Construct type objects. Construct is deeply cloned and persisted, having all its nested objects on the object graph being cloned too and getting a new Id (primary key). On every clone the diffId (from DiffEntity entity) stays the same (it serves the purpose of correlating objects for a diffing feature).
How would it be possible to search and get a reference for a specific DiffEntity given we have the below:
a reference to the Construnct instance
type of the nested object
diffId we are after.
I have tried different versions of object graph traversers with reflection, which will work for a small in size Construct object, but once it becomes too big performance is very slow.
Is there any magic on the entity manager itself to achieve that ?
Usually I'm able to Google my way out of asking questions here (thank you SO community), but I'm a bit stuck here. This problem has to do with propagating generated keys to joined objects when calling JpaRepository.save()
We have entities that are defined like so:
Parent object
#Entity
#Table(name = "appointment")
public class Appointment implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "APPT_ID", columnDefinition = "integer")
private Long apptId;
...
#OneToMany(targetEntity = ApptReminder.class, mappedBy = "appointment", cascade = {
CascadeType.MERGE, CascadeType.PERSIST}, fetch = FetchType.EAGER)
#NotFound(action = NotFoundAction.IGNORE)
private List<ApptReminder> apptReminders = new ArrayList<>();
}
Child Object:
#Entity
#Table(name = "appt_reminder")
public class ApptReminder implements Serializable {
#EmbeddedId
private ReminderKey reminderKey = new ReminderKey();
...
#ManyToOne
#NotFound(action = NotFoundAction.IGNORE)
private Appointment appointment;
}
Embedded Id Class
#Embeddable
public class ReminderKey implements Serializable {
#Column(name = "APPT_ID", columnDefinition = "integer")
private Long apptId;
#Column(name = "CALL_NUM", columnDefinition = "integer")
private Short callNum;
....
}
Repository:
public interface AppointmentRepository extends JpaRepository<Appointment, Long> {
}
And we have a bunch of sets of objects hanging off of the child object all sharing the embedded key attributes. When we call save on the parent object appointmentRepository.save(appointment) the child objects get saved, but the appt_id of the first appointment inserted gets an auto generated key of 1, and the first apptReminder record gets an appt_id of 0.
This affects all joined objects that share the embedded ID of ReminderKey with similar and predictable effects.
When we call appoitnmentRepository.save(appointment) on the top level entity, how do we get the autogenerated keys to propagate through to child entities? I feel like this should be very easy. Perhaps there's an element of the way I laid out the mappings or the usage of an embedded id that's preventing this from working.
One last thing of note is that this is running against an H2 database while in development, but will be used against MySQL afterwards. This could be attributable to H2's MySQL compatibility
I think you need to use JoinColumns annotation to marry Appointment apptId to ReminderKey apptId.
Solved this way:
Detach appointment from apptReminder on persist operations:
public class Appointment implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "APPT_ID", columnDefinition = "integer")
private Long apptId;
...
#OneToMany(targetEntity = ApptReminder.class, mappedBy = "appointment", cascade = CascadeType.DETACH, fetch = FetchType.EAGER)
#NotFound(action = NotFoundAction.IGNORE)
private List<ApptReminder> apptReminders = new ArrayList<>();
}
Create a DAO to handle persistence operations:
#Repository
public class AppointmentDAO {
#Autowired
private AppointmentRepository appointmentRepository;
#Autowired
private ApptReminderRepository apptReminderRepository;
public List<Appointment> save(List<Appointment> appointments) {
appointments.forEach(a -> this.save(a));
return appointments;
}
public Appointment save(Appointment appointment) {
final Appointment appt = appointmentRepository.save(appointment);
List<ApptReminder> apptReminders = appointment.getApptReminders();
apptReminders.forEach(a -> {
a.getReminderKey().setApptId(appt.getApptId());
a.getReminderTags().forEach(t -> t.setApptId(appt.getApptId()));
a.getReminderMessages()
.forEach(m -> m.getReminderMessageKey().setApptId(appt.getApptId()));
a.getMsgQueueReminder().setApptId(appt.getApptId());
});
apptReminderRepository.saveAll(apptReminders);
return appointment;
}
}
Good day!
I am triing to save my Entity model by always get an error
Error inserting bean [class models.CategoryEntity] with unidirectional relationship. For inserts you must use cascade save on the master bean [class models.CategoryEntity].]
Here my class
#Entity
public class CategoryEntity extends Model {
#Id
private String categoryId;
private String Name;
private Integer level;
#OneToMany(targetEntity = CategoryEntity.class, cascade = CascadeType.ALL)
private List<CategoryEntity> categories;
//GETERS SETRES
}
I tried to save the header category, but error is the same
If I understand the question correctly and what you want is that each CategoryEntity contains a list of other CategoryEntities, 2 possible approaches come to mind (although none of them use #OneToMany):
Approach 1:
You could create a #ManyToMany relationship and define a #JoinTable whilst naming its keys:
#Entity
public class CategoryEntity extends Model {
#Id
private String categoryId;
private String name;
private Integer level;
#ManyToMany(cascade=CascadeType.ALL)
#JoinTable( name = "category_category",
joinColumns = #JoinColumn(name = "source_category_id"),
inverseJoinColumns = #JoinColumn(name = "target_category_id"))
public List<CategoryEntity> category_entity_lists = new ArrayList<CategoryEntity>();
}
Approach 2:
Or you could create a new entity for the list of category entities and create a #ManyToMany relationship, e.g.:
#Entity
public class CategoryList extends Model
{
#Id
public Long id;
#ManyToMany
#JoinTable(name="categorylist_category")
public List<CategoryEntity> category_list = new ArrayList<CategoryEntity>();
}
And then in your model:
#Entity
public class CategoryEntity extends Model {
#Id
private String categoryId;
private String name;
private Integer level;
#OneToOne
public CategoryList this_category_list;
#ManyToMany(mappedBy="category_list")
public List<CategoryList> in_other_category_lists = new ArrayList<CategoryList>();
}
Didn't test the code, but what this should do is that each CategoryEntity can be part of several CategoryLists. Each CategoryList contains a list of CategoryEntities.
You would have to initialize this_category_list and add CategoryEntities to its category_list field.
Your model doesnt make sense.
why do you have as class attribute the class itself?
the List should not be in the same class