I have two classes: Furniture and Painting. Those are extending Item.
Item has the following code:
#Entity
public class Item implements Comparable, Serializable {
#Id #GeneratedValue(strategy= GenerationType.AUTO)
private Long id;
#ManyToOne
private User seller;
#Embedded
#AttributeOverrides({
#AttributeOverride(name = "description",
column = #Column(name = "c_description"))})
private Category category;
private String description;
public Item() {
}
public Item(User seller, Category category, String description) {
this.seller = seller;
this.category = category;
this.description = description;
this.seller.addItem(this);
}
Painting has the following code:
#Entity
public class Painting extends Item {
private String title;
private String painter;
public Painting() {
}
public Painting(String title, String painter, User seller, Category category, String description) {
super(seller, category, description);
this.title = title;
this.painter = painter;
}
Furniture has the following code:
#Entity
public class Furniture extends Item {
private String material;
public Furniture() {
}
public Furniture(String material, User seller, Category category, String description) {
super(seller, category, description);
this.material = material;
}
Before, I tried some code persisting the Item objects. That worked fine.
Now I'm trying to persist a Painting-object, persisting it through an Entity Manager.
I get the following error:
Object: auction.domain.Furniture#5d3468fd is not a known entity type.
It seems like I forgot something or did something wrong, probably in the Painting-class. What could it be?
I forgot to update my Persistence Unit. After adding the Furniture and Painting classes, the information got in to the database. Above code is correct.
Related
So, I'm trying to persist an entity in the database that has a composite key, declared using the #IdClass annotation, which one of the ID keys I have turned into an object so ensure some validation of the data.
Before, when this ID was just a String, it was working without any problems, but now that I have changed it's type, it seens that Hibernate can't determine it's type in the database.
I found a question with a problem that was almost exactly the same as the mine, here. After I added the #Column annotation to the fields in the IdClass, I feel that the Hibernate could determine the type of the field in the database, but now it fails to perform the conversion.
I already have the converter class with the #Converter annotation and implementing the AttributeConverter interface, but I think that it isn't being reached by the Spring/Hibernate.
The involved classes bellow:
The converter
#Converter
public class ChapterNumberConverter implements AttributeConverter<ChapterNumber, String> {
#Override
public String convertToDatabaseColumn(ChapterNumber attribute) {
String value = attribute.getValue();
return value;
}
#Override
public ChapterNumber convertToEntityAttribute(String dbData) {
ChapterNumber chapterNumber = new ChapterNumber(dbData);
return chapterNumber;
}
}
The composite ID class
public class ChapterID implements Serializable {
private static final long serialVersionUID = 4324952545057872260L;
#Column
private Long id;
#Column
#Convert(converter = ChapterNumberConverter.class)
private String number;
#Column
private Long publisher;
#Column
private Long manga;
public ChapterID() {
}
public ChapterID(Long id, String number, Long publisher, Long manga) {
this.id = id;
this.number = number;
this.publisher = publisher;
this.manga = manga;
}
// ... getters and setters
}
The entity class
#Entity
#Table(name = "chapter", uniqueConstraints = #UniqueConstraint(columnNames = {"number", "publisher_id", "manga_id"}))
#IdClass(ChapterID.class)
public class Chapter {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
#Id
#Convert(converter = ChapterNumberConverter.class)
private ChapterNumber number;
#Id
#ManyToOne
#JoinColumn(name = "publisher_id")
private Publisher publisher;
#Id
#ManyToOne
#JoinColumn(name = "manga_id")
private Manga manga;
#Column(nullable = false)
#Convert(converter = ChapterLanguageEnumConverter.class)
private ChapterLanguage language;
public Chapter() {
}
public Chapter(ChapterNumber chapterNumber, Publisher publisher, Manga manga, ChapterLanguage language) {
this.number = chapterNumber;
this.publisher = publisher;
this.manga = manga;
this.language = language;
}
public Chapter(String chapterNumber, Publisher publisher, Manga manga, ChapterLanguage language) {
this(new ChapterNumber(chapterNumber), publisher, manga, language);
}
// ... getters and setters
}
I just want to validate the number field in the entity class, so, if there is another way to do this without using a custom type, otherwise, if anyone knows what I can do to teach correctly the Hibernate how to persist this field, tell me please 😢
I have to map a composite PK with JPA in an Oracle DB.
I've followed other SO questions with relation to this tutorial but I'm still getting the following error:
java.sql.SQLSyntaxErrorException: ORA-00904: "COMPOSITEI0_"."NAME_1": Invalid Identifier (where NAME_1 relates to the name of one of the columns which are part of the PK)
This is my entity (real names not mentioned for data protection reasons):
#Entity
#Table(schema = "SCHEMA", name = "TABLE")
public class CompositeIdEntity {
#Column(name = "NAME1")
private String name1;
#Column(name = "NAME2")
private String name2;
#Column(name = "NAME3")
private String name3;
#EmbeddedId
CompositePrimaryKeyTableEmbeddable id;
public CompositePrimaryKeyTableEmbeddable getId() {
return this.id;
}
public void setId(CompositePrimaryKeyTableEmbeddable id) {
this.id = id;
}
// other getters and setters
My #Embeddable id class:
#Embeddable
public class CompositePrimaryKeyTableEmbeddable implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Column(name="name1")
private String name1;
#Column(name="name2")
private String name2;
public CompositePrimaryKeyTableEmbeddable() {
super();
}
public CompositePrimaryKeyTableEmbeddable(String name1, String name2) {
this.name1 = name1;
this.name2 = name2;
}
My #Repository:
#Repository
public interface CompositeIdDao extends JpaRepository<CompositeIdEntity, CompositePrimaryKeyTableEmbeddable> {
}
And finally call to the DB, which only returns null because it's just a test to see if it all works together:
public CompositeIdEto saveCompositeId() {
CompositeIdEntity compositeIdEto = new CompositeIdEntity();
compositeIdEto.setname3("New");
compositeIdEto.setId(new CompositePrimaryKeyTableEmbeddable("ERR", "ER"));
this.compositeIdDao.save(compositeIdEto);
return null;
}
It seems you are duplicating the name1 and name2 columns by declaring them once
in the entity itself and later in the embeddable.
You seem to only need the id embeddable and the name3 declaration in the entity:
#Entity
#Table(schema = "SCHEMA", name = "TABLE")
public class CompositeIdEntity {
#EmbeddedId
CompositePrimaryKeyTableEmbeddable id;
#Column(name = "NAME3")
private String name3;
I have nested models in a very simple Play application. I have a User model which looks like;
#Entity
public class User extends Model {
#Id
public Integer id;
#Constraints.Email
#Constraints.Required
public String email;
#Constraints.Required
private String password;
#ManyToOne
public City city;
}
And the City model looks like;
#Entity
public class City extends Model {
#Id
public Integer id;
public String name;
#ManyToOne
public Country country;
}
Which is again, very simple.
I then have the Country model, which is;
#Entity
public class Country extends Model {
#Id
public Integer id;
public String name;
}
Now, what I'm doing is POST-ing parameters email, password, and city_id to an action;
public static Result registerUser() {
Form<Register> registerForm = form(Register.class).bindFromRequest();
Logger.debug(registerForm.toString());
if (registerForm.hasErrors()) {
return badRequest(register.render(registerForm));
} else {
User user = form(User.class).bindFromRequest().get();
user.save();
return redirect(controllers.routes.Application.login());
}
}
The database I'm using is MySQL, and I can see the new User rows coming in. What I always see is that city_id stays null which wasn't what I had assumed.
I had assumed Hibernate to take care of the relationship between the objects and the corresponding database foreign keys, but that doesn't seem to be working.
I have a city with id = 1 entered into the city table already and that is the city_id I'm sending through POST.
What's going on here?
Suppose i want to have a composite key as street, city for purchase order entity.
Below is how i identify doing it,
#Embeddable
public class BillingAddress implements Serializable {
private String street;
private String city;
public BillingAddress(){
}
public BillingAddress(String street, String city) {
this.street = street;
this.city = city;
}
//with getters and setters
}
#Entity
#IdClass(BillingAddress.class)
public class PurchaseOrder {
public PurchaseOrder(BillingAddress billingAddress) {
street = billingAddress.getStreet();
city = billingAddress.getCity();
}
#Id
#AttributeOverrides({
#AttributeOverride(name = "street", column = #Column(name = "STREET")),
#AttributeOverride(name = "city", column = #Column(name = "CITY")) })
private String street;
private String city;
private String itemName;
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
}
I want to understand what is really #AttributeOverrides annotation do? Even i change to colomn name to something STREET1 i still see the table created with column name STREET. So what is column = #Column(name = "STREET")) doing here.
Also instead of constructore taking the BillingAddress i can have it like a field of PurchaseOrder class right like,
public class PurchaseOrder {
BillingAddress billingAddress;
}
In this case how this going to change?
Do i still need to have private String street; private String city; in PurchaseOrder?
Finally i read that using composite keys should be avoided in new data base system design which using composite primary key is applicable a situation where in order to map the legacy data base tables with out changing the data base table structure right? Is that statement a valid one?
//Edit question
Saving purchase order which billing address is in the field,
PurchaseOrder purchaseOrder = new PurchaseOrder();
purchaseOrder.setItemName("name");
BillingAddress billingAddress = new BillingAddress();
billingAddress.setCity("c1"); billingAddress.setStreet("s1"); purchaseOrder.setBillingAddress(billingAddress);
session.save(purchaseOrder);
There's are few question you asked, I tried to go through all of them and answer each one:
What does #AnnotationOverride do?
answer here: What does #AttributeOverride mean?
The second question is a bit unclear to me but I presume you're asking whether you have to include all the fields from the composite key in the PurchaseOrder class.
No, I don't think so. Here's an example I've put together real fast:
#Entity
#Table(name = "PURCHASE_ORDER")
public class PurchaseOrder{
#Id
private BillingAddress billingAddress;
//getters & setters
#Embeddable
public static class BillingAddress implements Serializable {
#Column(name = "street")
private String street;
#Column(name = "city")
private String city;
#Column(name = "itemName")
private String itemName;
//getters & setters
}
}
Don't worry about the syntax, just the structure. You can even add extra field into PurchaseOrder which isn't an id.
Should I use composite keys or not?
answer here: Should I use composite primary keys or not?
Well, your PurchaseOrder class does not extend from a mapped entity of any kind, and neither do the properties that you are (currently) applying the #AttributeOverrides to. So, there is nothing to actually override and your JPA provider is simply ignoring the annotations. What I think you are trying to do is define an embedded id for an entity, while overriding some of the column mappings for that id. You can do this with some modifications to your current code:
#Entity
public class PurchaseOrder {
#EmbeddedId
#AttributeOverrides({
#AttributeOverride(name = "street", column = #Column(name = "BILLING_STREET")),
#AttributeOverride(name = "city", column = #Column(name = "BILLING_CITY")) })
private BillingAddress billingAddress;
private String itemName;
// Constructors, Getters/Setters
}
Note that I've changed the names of the overridden attributes, since with your current example, the embedded id name and overridden names are the same.
I am developing a Java Desktop Application and using JPA for persistence. I have a problem mentioned below:
I have two entities:
Country
City
Country has the following attribute:
CountryName (PK)
City has the following attribute:
CityName
Now as there can be two cities with same name in two different countries, the primaryKey for City table in the datbase is a composite primary key composed of CityName and CountryName.
Now my question is How to implement the primary key of the City as an Entity in Java
#Entity
public class Country implements Serializable {
private String countryName;
#Id
public String getCountryName() {
return this.countryName;
}
}
#Entity
public class City implements Serializable {
private CityPK cityPK;
private Country country;
#EmbeddedId
public CityPK getCityPK() {
return this.cityPK;
}
}
#Embeddable
public class CityPK implements Serializable {
public String cityName;
public String countryName;
}
Now as we know that the relationship from Country to City is OneToMany and to show this relationship in the above code, I have added a country variable in City class.
But then we have duplicate data(countryName) stored in two places in the City class' object: one in the country object and other in the cityPK object.
But on the other hand, both are necessary:
countryName in cityPK object is necessary because we implement composite primary keys in this way.
countryName in country object is necessary because it is the standard way of showing relashionship between objects.
How to get around this problem?
countryName in CityPK should be marked read-only using #Column(insertable = false, updatable = false) and both countryNames should be mapped to the same column (using name property):
#Entity
public class City implements Serializable {
#EmbeddedId
private CityPK cityPK;
#ManyToOne
#JoinColumn(name = "countryName")
private Country country;
}
#Embeddable
public class CityPK implements Serializable {
public String cityName;
#Column(name = "countryName", insertable = false, updatable = false)
public String countryName;
}
IMO the proper way to deal with such issues would be to use a generated internal (typically Long) ID instead of a natural primary key - this eliminates the whole problem. Of course, this requires a modification of your DB schema, but from your post I assume that this is possible.
#Entity
public class City implements Serializable {
private Long id;
private String name;
private Country country;
#Id
#GeneratedValue
#Column(name = "CITY_ID")
public Long getId() {
return this.id;
}
private void setId(Long id) {
this.id = id;
}
// more getters, setters and annotations
}