I have two classes Cards and CardBalance. In my DB sсhema table card_balance has foreign key on table cards. But in ORM I want that entity Cards has properties CardBalance, and entity CardBalance does't have propertie Cards.
I try do this in next way:
#Entity
#Table(name = "CARD_BALANCE")
public class CardBalance {
#Id
#Column(name = "BALANCE_ID")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CARD_BALANCE_SEQ")
#SequenceGenerator(name = "CARD_BALANCE_SEQ", sequenceName = "CARD_BALANCE_SEQ")
private Long balanceId;
#Column(name="CARD_ID")
private Long cardId;
}
#Entity
#Table(name = "CARDS")
public class Cards implements Serializable {
#Id
#Column(name = "CARD_ID")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CARDS_SEQ")
#SequenceGenerator(name = "CARDS_SEQ", sequenceName = "CARDS_SEQ")
private Long cardId;
#Column(name = "CARD_NAME", length = 30, unique = true)
private String cardName;
#Column(name="PERSON_ID")
private Long personId;
#Column(name = "CARD_KEY", nullable = false)
private long cardKey;
#OneToOne
#JoinColumn(name="TYPE_ID", nullable = false)
private TypeCard typeCard;
#OneToOne
#JoinColumn(name="CARD_ID", nullable = false)
private CardBalance cardBalance;
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(name="CARD_ID")
public Set<BalanceHist> balanceHists = new HashSet<>();
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(name="CARD_ID")
public Set<Events> events = new HashSet<>();
}
but it does't work. How I can solve this problem?
First of all, you have a mistake in your #JoinColumn, it should be:
#OneToOne
#JoinColumn(name="BALANCE_ID", nullable = false)
private CardBalance cardBalance;
Related
I am studying a training project - working with databases.
Here is a class describing the entity
#Entity
#Table(name = "pricelists", schema = "inventories")
public class PriceList {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "id_inventory", insertable = false, updatable = false)
private Long idInventory;
#ManyToOne
#JoinColumn(name = "id_inventory", nullable = false)
private Inventory inventory;
private Integer price;
}
And there are two variables that refer to the same "id_inventory" field in the database table. Is it possible to do this? Is this not a mistake?
You should leave that
#Entity
#Table(name = "pricelists", schema = "inventories")
public class PriceList {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name = "id_inventory", nullable = false)
private Inventory inventory;
private Integer price;
}
I hope that will work.
I have a tree-like data structure in my application.
For example, main entity is DraftDoc, it has a child entity DraftEffect. And DraftEffect has its own child entity DraftOffenderCategory.
What is the best strategy for persisting the data to the database?
To collect the whole tree on the front-end side to one big JSON and persist everything at once?
Or to take DraftDoc data (not including related entities) and persist, then take DraftEffect data and persist and so on?
#Entity
#Table(name = "TN_DRAFT_DOCS")
public class DraftDoc implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "DRAFTDOC_SEQ")
#SequenceGenerator(name = "DRAFTDOC_SEQ", sequenceName = "NT_DRAFT_DOC_SEQ")
#Column
private Long id;
#Column(name = "ARTICLE_ID")
private Long articleId;
#Column(name = "ARTICLE_VERSION")
private Long articleVersion;
#OneToMany(cascade={CascadeType.ALL},fetch=FetchType.LAZY)
#JoinTable(name = "TN_DRAFT_R_DOC_EFF", joinColumns = { #JoinColumn(name = "doc_id", referencedColumnName = "id") }, inverseJoinColumns = { #JoinColumn(name = "eff_id", referencedColumnName = "id") })
private List<DraftEffect> effects;
...
}
#Entity
#Table(name = "TN_DRAFT_EFFECT")
public class DraftEffect {
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "DRAFT_EFFECT_SEQ")
#SequenceGenerator(name = "DRAFT_EFFECT_SEQ", sequenceName = "NT_DRAFT_EFFECT_SEQ")
#Column
private Long id;
#Column(name = "ARTICLE_ID")
private Long articleId;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "effect")
private List<DraftAffection> affections;
...
}
#Entity
#Table(name = "TN_DRAFT_AFFECTION")
public class DraftAffection implements Serializable {
private static final long serialVersionUID = 3048761786638684368L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "DRAFTAFFECTION_SEQ")
#SequenceGenerator(name = "DRAFTAFFECTION_SEQ", sequenceName = "NT_DRAFT_AFFECTION_SEQ")
#Column
private Long id;
#Column(name = "ARTICLE_ID")
private Long articleId;
...
}
I have the following code for many to many or many to one relationship persistence using Spring JPA.
This is my repository test https://github.com/Truebu/testJpa.git
This class has three one-to-many relationships, but none work well
#Entity(name = "routine_assignament")
#Table(name = "routine_assignament")
public class RoutineAssignament {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", updatable = false)
private Long id;
#Column(name = "date_start",nullable = true,columnDefinition = "DATE")
private Date date_start = new Date();
#Column(name = "date_end",nullable = true,columnDefinition = "DATE")
private Date date_end;
#ManyToOne
#JoinColumn(name = "id_user")
private User user;
#ManyToOne
#JoinColumn(name = "id_routine")
private Routine routine;
#OneToMany(mappedBy = "routine_assignament")
private Set<Score> scores = new HashSet<>();
#OneToMany(mappedBy = "routine_assignament")
private Set<Statistic> statistics = new HashSet<>();
#OneToMany(mappedBy = "routine_assignament")
private Set<KeepRoutine> keepRoutines = new HashSet<>();
The other classes
#Entity(name = "score")
#Table(name = "score")
public class Score {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", updatable = false)
private Long id;
#Column(name = "commentary",nullable = false,columnDefinition = "TEXT", unique = true)
private String commentary;
#Column(name = "assessment",nullable = false,columnDefinition = "INT", unique = true)
private String assessment;
#ManyToOne
#JoinColumn(name = "id_routine_assignament")
private RoutineAssignament routineAssignament;
}
#Entity(name = "statistic")
#Table(name = "statistic")
public class Statistic {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", updatable = false)
private Long id;
#Column(name = "time",nullable = false,columnDefinition = "TEXT", unique = true)
private String time;
#ManyToOne
#JoinColumn(name = "id_routine_assignament")
private RoutineAssignament routineAssignament;
}
and
#Entity(name = "keep_routine")
#Table(name = "keep_routine")
public class KeepRoutine {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", updatable = false)
private Long id;
#ManyToOne
#JoinColumn(name = "id_routine_assignament")
private RoutineAssignament routineAssignament;
}
The entity relationship diagram is this:
My mistake is that it doesn't detect these relationships correctly.
When I run it it generates this:
Failed to initialize JPA EntityManagerFactory: mappedBy reference an unknown target entity property: com.example.demo.model.entities.KeepRoutine.routine_assignament in com.example.demo.model.entities.RoutineAssignament.keepRoutines
This error is reproduced with all three classes (KeepRoutine, Statistic and Score), I don't know why
Your OneToMany mapping is not appropriate. You need to use routineAssignament the property name instead of the table name routine_assignament as shown below. This property name is defined in the ManyToOne relationship.
#OneToMany(mappedBy = "routineAssignament")
private Set<Score> scores = new HashSet<>();
#OneToMany(mappedBy = "routineAssignament")
private Set<Statistic> statistics = new HashSet<>();
#OneToMany(mappedBy = "routineAssignament")
private Set<KeepRoutine> keepRoutines = new HashSet<>();
See code below for my 2 entity classes - when I call the findAll() method from my OrigRepository class, it joins these two tables using both primary keys. I want the join to be between the primary key of the Orig table and the foreign key entry in the MsgResponse table ("OrigID") - any sugggestions?
Orig Entity
#Entity
#Table(name = "originator")
public class Orig {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "OrigID")
private int OrigID;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "OrigID")
private MsgResponse responseInfo;
}
MsgResponse Entity
#Entity
#Table(name = "message_response")
public class MsgResponse {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private int responseId;
#Column(name = "OrigID")
private int OrigId;
#OneToOne(mappedBy="responseInfo")
private Orig OrigInfo;
}
I suggest you to see the jpa documentation
here.
Example 1 should be your case
Try to swap relation ownership, that is:
#Entity
#Table(name = "originator")
public class Orig {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "OrigID")
private int OrigID;
#OneToOne(mappedBy="origInfo")
private MsgResponse responseInfo;
}
#Entity
#Table(name = "message_response")
public class MsgResponse {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private int responseId;
// #Column(name = "OrigID")
// private int origId;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "OrigID")
private Orig origInfo;
}
Note that the #JoinColum annotation is in now in the MsgResponse entity. This is because in a #OneToOne the join column refers to the source entity (see here).
Hope this could help.
This are my entities:
public class Account extends AbstractEntity<Long> {
#Id
#SequenceGenerator(name = "accountSequence", sequenceName = "SQ_ACCOUNTS", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "accountSequence")
#Column(name = "ACC_ID", nullable = false)
private Long id;
...
}
public class Integration extends AbstractEntity<Long> {
#Id
#SequenceGenerator(name = "integrationSequence", sequenceName="SQ_INTEGRATIONS", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "integrationSequence")
#Column(name = "INT_ID", nullable = false)
private Long id;
...
public void addIntegration(Integration integration) {
IntegrationAccount association = new IntegrationAccount();
// This does not help
//association.setIntAccountsPK(new IntAccountsPK(integration.getId(), this.getId()));
association.setAccount(this);
association.setIntegration(integration);
this.integrationAccounts.add(association);
integration.getIntAccountsCollection().add(association);
}
}
And this is entity for join table
#Entity
#Table(name = "INT_ACCOUNTS")
public class IntegrationAccount {
#EmbeddedId
protected IntAccountsPK intAccountsPK;
#JoinColumn(name = "ACC_ID", referencedColumnName = "ACC_ID", insertable = false, updatable = false)
#ManyToOne
private Account account;
#JoinColumn(name = "INT_ID", referencedColumnName = "INT_ID", insertable = false, updatable = false)
#ManyToOne
private Integration integration;
...
}
#Embeddable
public class IntAccountsPK implements Serializable {
#Column(name = "INT_ID", nullable = false)
private Long intId;
#Column(name = "ACC_ID", nullable = false)
private Long accId;
...
}
And when i do:
account.addIntegrations(integrations.getTarget());
account.setCustomer(customer);
accountService.save(account);
I got this in my log
Caused by: org.hibernate.id.IdentifierGenerationException: null id generated for:class com.dhl.dcc.domain.IntegrationAccount
I dont have many knowledge about this kind of mapping, can you please tell me how to improve this mapping (entity for join table have to be preserved) and how to save account with related integrations? Thanks.
I know this question has already been marked as solved but I disagree with the accepted answer. This answer modifies the datamodel by adding a useless column (the new id) in the table INT_ACCOUNTS. There is another way to solve this problem in Hibernate without modifying the datamodel :
#Entity
#Table(name = "INT_ACCOUNTS")
public class IntegrationAccount implements Serializable {
#Id
#ManyToOne
#JoinColumn(name = "INT_ID_FK")
private Integration integration;
#Id
#ManyToOne
#JoinColumn(name = "ACC_ID_FK")
private Account account;
}
#Entity
#Table(name = "INTEGRATIONS")
public class Integration {
#Id
#SequenceGenerator(name = "integrationSequence", sequenceName = "SQ_INTEGRATIONS", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "integrationSequence")
#Column(name = "INT_ID")
private Long id;
}
#Entity
#Table(name = "ACCOUNTS")
public class Account {
#Id
#SequenceGenerator(name = "accountSequence", sequenceName = "SQ_ACCOUNTS", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "accountSequence")
#Column(name = "ACC_ID")
private Long id;
}
You could create a ID field for your IntegrationAccount and then create a unique constraint for your two fields.
#Entity
#Table(name = "INT_ACCOUNTS",
uniqueConstraints=#UniqueConstraint(columnNames={"ACC_ID", "INT_ID"}))
public class IntegrationAccount {
#Id
private Long id;
#JoinColumn(name = "ACC_ID", referencedColumnName = "ACC_ID", insertable = false, updatable = false)
#ManyToOne
private Account account;
#JoinColumn(name = "INT_ID", referencedColumnName = "INT_ID", insertable = false, updatable = false)
#ManyToOne
private Integration integration;
...
}
Works like a charm!