I have the following class
#MappedSuperclass
public class Keyword {
private Integer code;
private Integer rating;
public Keyword() {}
public Integer getCode() {
return this.code;
}
public Integer getRating() {
return this.rating;
}
public void setCode(Integer code) {
this.code = code;
}
public void setRating(Integer rating) {
this.rating = rating;
}
}
I want to create an Entity by extending this class and I want to set an already existing field as the primary key (I don't want to create new fields), so I tried to do something like this:
#Entity
#Table(name = "keyword")
//#AttributeOverride(name = "code", column = #Column(name = "code"))
public class MyKeyword extends Keyword {
#Override
#Id
#GeneratedValue
public Integer getCode() {
return super.getCode();
}
}
This gives me the following error when ran
Caused by: org.hibernate.MappingException: Repeated column in mapping
for entity: com.foo.model.MyKeyword column: code (should be mapped
with insert="false" update="false")
Any idea how can I properly configure this up? Keep in mind I have no access to the MappedSuperclass, I can't modify it whatsoever.
Related
I have a problem with the hibernate entity, and I would like to know if it is something I overlooked or if it is a bug in IntelliJ IDEA.
I have a Value object bank account:
class BankAccount
{
private String value;
public BankAccount(String value) {
// validation
this.value;
}
}
Which has defined it's own hibernate type:
public class BankAccountType extends AbstractSingleColumnStandardBasicType<BankAccount> {
public static final BankAccountType INSTANCE = new BankAccountType();
public static final String NAME = "bankAccount";
public BankAccountType() {
super(LongVarcharTypeDescriptor.INSTANCE, BankAccountTypeDescriptor.INSTANCE);
}
#Override
public String getName() {
return null;
}
}
And I have an entity:
#Entity
#TypeDefs({
#TypeDef(
name = BankAccountType.NAME,
typeClass = BankAccountType.class,
defaultForType = BankAccount.class
)
})
class User {
private UUID id;
//...
#Column
private BankAccount bankAccount;
//...
}
It works perfectly, but IDEA keeps telling me 'Basic attribute should not be BankAccount.'
Is there any way, how to get rid of this error without changing my entities? Is it a good idea to use value objects as a column in my entities?
Thanks a lot!
I have an Entity that would like to extend it by adding some fields. first of all they are not accessible to me to change directly, they are in their own jar file. here are the base entities:
#Entity
table(name="ACCOUNTDEF")
public class EtAccountDef
{
private String cNumber;
private List<EtAccount> accounts = new ArrayList();
public String getCNumber()
{
return cNumber;
}
public void setCNumber(String cNumber) {
this.cNumber = cNumber;
}
#OneToMany(fetch=FetchType.LAZY, cascade={javax.persistence.CascadeType.ALL}, mappedBy="accountDef")
public List<EtAccount> getAccounts() {
return accounts;
}
public void setAccounts(List<EtAccount> accounts) {
this.accounts = accounts;
}
}
which is the parent class and the below is child class:
#Entity
#Table(name="ACCOUNT")
public class EtAccount
{
private Double accountAmount;
private EtAccountDef accountDef;
private List<EtAccountItems> accountItems = new ArrayList();
#ManyToOne(fetch=FetchType.LAZY)
public EtAccountDef getAccountDef() {
return accountDef;
}
public void setAccountDef(EtAccountDef accountDef) {
this.accountDef = accountDef;
}
#OneToMany(fetch=FetchType.LAZY, cascade={javax.persistence.CascadeType.ALL}, mappedBy="account")
public List<EtAccountItems> getAccountItems() {
return accountItems;
}
public void setAccountItems(List<EtAccountItems> accountItems) {
this.accountItems = accountItems;
}
}
so I tried these changes to achieve my goal.
#MappedSuperclass
public abstract class OtAbstractAccount extends EtAccount {
private Double AccountCommission;
#Column(columnDefinition="decimal(15,2)")
public Double getAccountCommission() {
return accountCommission;
}
public void setAccountCommission(Double accountCommission) {
this.accountCommission = accountCommission;
}
and then extend it by this entity:
#Entity
#Table(name="ACCOUNT")
public class OtCostumAccount extends OtAbstractAccount {
}
The fields are now added to the base table(EtAccount) but
after compiling I get an error in the Weblogic that says:
Caused by: org.hibernate.AnnotationException: #OneToOne or #ManyToOne
on EtAccount.accountDef references an unknown entity: EtAccountDef
I have entered these two line in my ORM file:
<mapped-superclass class="package.OtAbstractAccount" />
<entity class="package.OtCostumAccount" />
Surprisingly when i comment
<mapped-superclass class="package.OtAbstractAccount" />
from ORM the weblogic does not rise any error but when I try to load object another error will be created that say:
Caused by: javax.persistence.PersistenceException:
org.hibernate.exception.SQLGrammarException: ORA-00904:
"OtCostumAccount "."DTYPE": invalid identifier
I'm confused whit these error and I'll appreciate any help.
If you can not modify the parent class, then the default hibernate inheritance strategy apply: one table per class. This strategy require a discriminant column which, by default, is DTYPE. Did you try to add a discriminator column to your OtCostumAccount entity or create the DTYPE column ?
I am creating a REST api service for a mysql database. I've generated classes using IntelliJ's persistence tool. It does a pretty good job.
There are some quirks to the schema that I am working with. The users want the endpoints to be accessible by another property other than the "id" primary key column.
Ex: /object/<name property>' versus/object/`.
Here is the catch though. The schema can change. The name property is not going anywhere though so I can safely assume that will always be on the object.
I've learned that you can use Superclasses to force these generated entites to have custom properties without affecting the database schema. I dont want to make a model change in the generated entity and have that update the database table layout as it is not my database.
I have a class called Animal.
#Entity
#Table(name = "animals", schema = "xyz123", catalog = "")
public class AnimalEntity extends AnimalSuperclass {
private Integer id;
private String name;
private String description;
#Id
#Column(name = "id", nullable = false)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#Basic
#Column(name = "name", nullable = true, length = 80)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Basic
#Column(name = "description", nullable = true, length = 255)
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RoleEntity that = (RoleEntity) o;
return Objects.equals(id, that.id) &&
Objects.equals(name, that.name) &&
Objects.equals(description, that.description);
}
#Override
public int hashCode() {
return Objects.hash(id, name, description);
}
}
I have to manually add extends AnimalSuperclass. Which is fine for now. Eventually I am going to try to generate these using .xmls on runtime.
Then I have this superclass..
#MappedSuperclass
public class AnimalSuperclass implements Serializable {
private String testMessage;
private String name;
private Integer id;
#Transient
public String getTestMessage() {
return this.testMessage;
}
public void setTestMessage(String id) {
this.testMessage = testMessage;
}
}
What I want to do is force the #Id annotation to be on the name property from within the superclass. Something like this..
#MappedSuperclass
public class AnimalSuperclass implements Serializable {
private String testMessage;
private String name;
private Integer id;
#Transient
public String getTestMessage() {
return this.testMessage;
}
public void setTestMessage(String id) {
this.testMessage = testMessage;
}
#Basic
#Id
#Column(name = "name", nullable = false, length = 15)
private String getName() {
return name;
}
private void setName(String name) {
this.name = name;
}
#NaturalId
#Column(name = "id", nullable = false)
private Integer getId() {
return id;
}
private void setId(Integer id) {
this.id = id;
}
}
How do I go about doing that? Currently this throws an error when I hit the endpoint: {"cause":null,"message":"Id must be assignable to Serializable!: null"}
Java is not my first language so I am not an expert by any means. But from what I've read, its not possible to override subclass properties from the superclass. Is there a better way to approach this, maybe by using RepositoryRestConfiguration? I am using PagingAndSortingRepository to serve these entities. I cannot extend the entities and use my superclass as a child as that creates a dType property in the schema and I cannot alter the table layout.
There is no hard link between the request and your entity. In your repository you can write methods that can query the data that is brought it from the request.
For example if they are requesting a name you can do something like
Page<AnimalEntity> findByName(String name, Pageable pageable);
in your Repository. Spring will take care of the rest and then you can call this in your controller.
#Service
public class AnimalService {
#Autowired
private AnimalEntityRepository animalRepo;
public Page<AnimalEntity> findAnimal(String name) {
Page<AnimalEntity> animals = animalRepo.findByName(name, new PageRequest(1,20));
return animals;
}
}
One thing to mention is that depending on how you configured Hibernate when sending an entity back to the client and the entity is seralized you might get an failed to lazy initialize error. If that is the case your entities will have to be converted to a POJO (plain old java object) and that sent back.
(Using Spring 3.1 and hibernate 3.3)
I am using an IdClass with an entity that maps to a table that has 3 columns as a composite key.
My tests are failing throwing a runtime exception MappingException complaining that hibernate cannot determine the type for one of my columns used as part for the composite key. in this case it is the set column (aka in the db table as "set_id").
Here is a cut down version of my entity
#Entity
#Table(name = "the_table")
#IdClass(CompositeKey.class)
public class MyEntity {
#Id
#Column(name = "page_id")
private Integer pageId;
#Id
#Column(name = "xml_id")
private Integer xmlId;
#Id
#ManyToOne
#JoinColumn(name = "set_id")
private CustomSet set;
public CustomSet getSet() {
return set;
}
public void setSet(CustomSet set) {
this.set = set;
}
public Integer getPageId() {
return pageId;
}
public void setPageId(Integer pageId) {
this.pageId = pageId;
}
public Integer getXmlId() {
return xmlId;
}
public void setXmlId(Integer xmlId) {
this.xmlId = xmlId;
}
}
Here is the composite key id class
public class CompositeKey implements Serializable {
private Integer pageId;
private Integer xmlId;
private CustomSet set;
public CompositeKey(){}
public CompositeKey(Integer pageId, Integer xmlId, CustomSet set){
this.pageId = pageId;
this.xmlId = xmlId;
this.set = set;
}
public Integer getPageId() {
return pageId;
}
public Integer getXmlId() {
return xmlId;
}
public CustomSet getSet() {
return set;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof CompositeKey)) return false;
CompositeKey that = (CompositeKey) o;
if (!getPageId().equals(that.getPageId())) return false;
if (!getXmlId().equals(that.getXmlId())) return false;
return getSet().equals(that.getSet());
}
#Override
public int hashCode() {
int result = getPageId().hashCode();
result = 31 * result + getXmlId().hashCode();
result = 31 * result + getSet().hashCode();
return result;
}
}
I found that the answer was simple enough, I needed to annotate the "set" column in the composite key class with the same mapping type as in the entity.
Also because I have table column names that are different in to the variable names in the code, I had to add the extra column annotations to the variables in the composite key class as well.
here is the code change I made to the CompositeKey...
#Column(name = "page_id")
private Integer pageId;
#Column(name = "xml_id")
private Integer xmlId;
#ManyToOne
#JoinColumn(name = "set_id")
private CustomSet set;
That's it, now hibernate knows what type of mapping and column names to use with that database table. I had assumed it would pick that all up from the entity, but I guess not.
I had a similar issue, and I solved it by just adding the annotation #ManyToOne and #JoinColumn, to one of the Primary Keys (I was unfortunately missing) on the main class. Posting here just in case someone did the same mistake.
Actually adding annotations for the attributes on the composite key caused errors for me. I don't thinks that would be the correct approach.
I am trying to insert into many to many relationship using hibernate but I am getting this error.
2014-04-24 14:50:47,820 ERROR [BasicPropertyAccessor.java:118] : IllegalArgumentException in class: com.jellboi.maniartyre.entities.AbstractEntity, setter method of property: pkey
2014-04-24 14:50:47,827 ERROR [BasicPropertyAccessor.java:122] : expected type: java.lang.Long, actual value: org.hibernate.id.IdentifierGeneratorHelper$2
Apr 24, 2014 2:55:25 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet applicationController threw exception
java.lang.IllegalArgumentException: java.lang.ClassCastException#17d66f6
at sun.reflect.GeneratedMethodAccessor27.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
Here is the code that I am trying.
VehicleProduct class
#Entity
#Table(name="m_vehicle_product")
#AssociationOverrides({
#AssociationOverride(name = "pk.vehicle",
joinColumns = #JoinColumn(name = "vehicle_id")),
#AssociationOverride(name = "pk.product",
joinColumns = #JoinColumn(name = "product_id")),
})
public class VehicleProduct extends AbstractEntity{
private String service;
private VehicleProductId pk = new VehicleProductId();
#Column(name = "service")
public String getService() {
return service;
}
public void setService(String service) {
this.service = service;
}
#EmbeddedId
public VehicleProductId getPk() {
return pk;
}
public void setPk(VehicleProductId pk) {
this.pk = pk;
}
#Transient
public Product getProduct(){
return getPk().getProduct();
}
public void setProduct(Product product){
getPk().setProduct(product);
}
#Transient
public Vehicle getVehicle(){
return getPk().getVehicle();
}
public void setVehicle(Vehicle vehicle){
getPk().setVehicle(vehicle);
}
}
VehicleProductId Class
#Embeddable
public class VehicleProductId implements java.io.Serializable {
private Vehicle vehicle;
private Product product;
#ManyToOne
public Vehicle getVehicle() {
return vehicle;
}
public void setVehicle(Vehicle vehicle) {
this.vehicle = vehicle;
}
#ManyToOne
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
}
And this is how I am Inserting.
for(int i=0;i<jobid.length;i++){
product = productService.findByPkey(jobid[i]);
vehicleProduct.setProduct(product);
vehicleProduct.setService(jobdesc[i]);
pkey2 = vehicleProductService.save(vehicleProduct);
}
Please guide me on this. Trying since hours to solve this problem.
EDIT
#MappedSuperclass
public class AbstractEntity implements IEntity, Serializable{
private static final long serialVersionUID = 1L;
private Long pkey;
private Boolean deleted;
private String creator;
private Date created;
private String changer;
private Date changed;
private Long version;
#Id
#GeneratedValue
#Column(name="pkey")
public Long getPkey() {
return pkey;
}
public void setPkey(Long pkey) {
this.pkey = pkey;
}
#Column(name="deleted")
#XmlTransient
public Boolean getDeleted() {
return deleted;
}
public void setDeleted(Boolean deleted) {
this.deleted = deleted;
}
#Column(name="creator")
public String getCreator() {
return creator;
}
}........
It contains all of these getter and setters.
Your main problem is this:
2014-04-24 14:50:47,820 ERROR [BasicPropertyAccessor.java:118] : IllegalArgumentException in class: com.jellboi.maniartyre.entities.AbstractEntity, setter method of property: pkey
2014-04-24 14:50:47,827 ERROR [BasicPropertyAccessor.java:122] : expected type: java.lang.Long, actual value: org.hibernate.id.IdentifierGeneratorHelper$2
If you look at your code, you have an #Id defined on your AbstractEntity and an #EmbeddedId on your VehicleProduct
I am not sure how your database table is supposed to look, but it will seem to include the columns in AbstractEntity as well as those defined in VehicleProduct. If the columns are not meant to be there, then you shouldn't inherit from AbstractEntity. If they were meant to be there, then consider making the #EmbeddedId into an #Embedded and enforce a unique constraint for the business key.
2014-04-24 14:50:47,820 ERROR [BasicPropertyAccessor.java:118] : IllegalArgumentException in class: com.jellboi.maniartyre.entities.AbstractEntity, setter method of property: pkey
2014-04-24 14:50:47,827 ERROR [BasicPropertyAccessor.java:122] : expected type: java.lang.Long, actual value: org.hibernate.id.IdentifierGeneratorHelper$2
I do not know it this is your case, but taking a look to your trace I have to say hibernate does not support composite PK's with an identity part
Hibernate Jira composite PK identity part