I have the class Person mapped with annotations with enum Sex reffering to the sex if is male or female. Let's see:
#Entity
#Table(name = "PERSON")
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Enumerated(EnumType.STRING)
#Column(name = "SEX")
private Sex sex;
private enum Sex {
M,
F;
}
// Getters, setters & constructors
}
When I test getting all the rows from the MySQL database, it works and the mapping is correct.
The database is already predefined, here is the column's definition:
`SEX` enum('M','F') NOT NULL
However the error occurs when I configure Hibernate with hibernate.hbm2ddl.auto=validate:
found [enum (Types#CHAR)], but expecting [varchar(255) (Types#VARCHAR)]
The error is a bit different (expecting [integer (Types#INTEGER)]) happend when I use EnumType.ORDINAL or no #Enumerated at all.
What do I do wrong?
try add columnDefinition
#Enumerated(EnumType.STRING)
#Column(name = "SEX" , columnDefinition="ENUM('M','S')" ,nullable = false )
private Sex sex;
hibernate validate do check types , lenght.... as you have this in db level validator thinks it's different type .
I didn't see it with Oracle , but with MySql it's might be
Related
I have a problem while building a OneToMany relationship between two entities. I have a user who can have multiple Properties. I want to define this relationship and create tables in MySql however when I run it it gives me Exception in thread "main" java.lang.NullPointerException
at start.ApplicationStart.main(ApplicationStart.java:44)
and also there are 2 more columns in the user table in mysql "user_id" and city. Now what I defined so far in my code is:
in class user I have the following fields:
#Id
private String id;
#OneToMany(mappedBy = "user",cascade = CascadeType.ALL) //mapped by variable in class user
private List<Properties> properties;
and in class Properties I have:
#Column(name = "city")
private String city;
#Column(name = "address", nullable = false)
private String address;
#ManyToOne
#JoinColumn(name="user_id")// , nullable=false
private User user;
I don't understand why I have the extra columns in the user table. Also I am using entity manager for both tables. Any hint would be great
I had a column useless_id in table foo. This column is foreign key into other table.
I have mapped it like this
#Entity
#Table(name = "foo")
public class Foo{
#Column(name = "useless_id")
private Integer uselessId;
//...
}
Everything worked perfect. But I decided to change the name of column useless_id into useful_id.
After that appear problems. When I try to save an Foo object: session.save(new Foo(...)) I get Unknown column F.useless_id in 'where clause'.
The query is printed in console insert into foo (..., useful_id, ...) value (...)
In list of columns I don't see useless_id.
Why I get Unknow column useless_id in 'where clause' ? Why use where when insert?
It is was changed everywhere. Even in Foo object
I get this error only when try to save.
UPDATE(Foo class is Order Class and useful_id is customer_id):
#Entity
#Table(name = "orders")
public class Order{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "status")
private Integer status;
#Column(name = "customer_id")
private Integer customerId;
#Column(name = "shipping_address")
private String shippingAddress;
//setters getters
}
#Entity
#Table(name = "customers")
public class Customer{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "name")
private String name;
//setters getters
}
This is how I try to insert new object
//...
session.beginTransaction();
Order order = new Order();
//set random values. customer_id get valid value, it exists in customers
session.save(order);
session.getTransaction().commit();
session.close();
For DESCRIBE orders; command I get:
Field----------------Type-----------Null---Key---Default---Extra
id-------------------int(11)--------NO-----PRI---NULL------auto_increment
status---------------int(50)--------NO-----------NULL------
customer_id----------int(50)--------NO-----MUL---NULL------
shipping_address-----varchar(191)---NO-----------NULL------
I found the problem.
It raised from MySQL. I found it by tried to insert with SQL command, direct to MySQL. Same error.
So I was looking very carefully in db and I found the problem is from triggers. In one of triggers still use old name of column.
Now make sense: Unknow column useless_id in 'where clause'. That where clause was in trigger which try to find useless_id, but it no longer exists.
CONCLUSION: After change name of column, check triggers.
In your java class you changes column name from useless_id to userful_id, but same think you didnt changes in your DB structure due to which you see this error.
I'm mapping a relationship that does not use the entity's primary key. Using "referencedColumnName" with a column different than the primary key causes hibernate to eagerly fetch the association, by issuing an extra select, even when it's tagged with FetchType.LAZY.
My goal is to make it behave like a regular mapping, meaning it wouldn't issue an extra query every time I need to query the main entity.
I have already tried using #LazyToOne(LazyToOneOption.NO_PROXY), which sorts out the problem, but it does not operate well with Jackson's (JSON parsing library) module "jackson-datatype-hibernate5", which skips hibernate lazy proxies when serializing the results.
Here is a scenario almost like the one I have that causes the problem:
Entities:
#Entity(name = "Book")
#Table(name = "book")
public class Book
implements Serializable {
#Id
#GeneratedValue
private Long id;
private String title;
private String author;
#NaturalId
private String isbn;
//Getters and setters omitted for brevity
}
#Entity(name = "Publication")
#Table(name = "publication")
public class Publication {
#Id
#GeneratedValue
private Long id;
private String publisher;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(
name = "isbn",
referencedColumnName = "isbn"
)
private Book book;
#Column(
name = "price_in_cents",
nullable = false
)
private Integer priceCents;
private String currency;
//Getters and setters omitted for brevity
}
Repository (Spring-Data, but you could try directly with the EntityManager):
#Repository
public interface PublicationRepository extends JpaReadRepository <Publication, Long>
{
#Query ("SELECT d FROM Publication d WHERE d.publisher = ?1 ")
Optional <Publication> findByPublisher (String isbn);
}
Thanks
The only way to achieve what you are looking for is by moving the annotatation #Id to the isbn property.
You can leave the #GeneratedValue on the autoincrement property.
Notes:
1 - Make sure that your equals/hc are following the OID(Object ID) on your domain case the "NaturalId" ISBN.
2 - It will be good to ensure if possible on DB level that your natural ID has unique contraint on it.
I have main entity:
#Entity
#Table(name = "partners")
public class Partner {
#ElementCollection
#CollectionTable(
name = "external_login",
joinColumns = #JoinColumn(name = "partner_id")
)
private List<ExternalLogin> externalLogins;
...
}
And ExternalLogin is embeded entity
#Embeddable
public class ExternalLogin {
#Column(name = "type")
#Enumerated(value = EnumType.STRING)
private ExternalLoginType type;
#Column(name = "login")
private String login;
#Column(name = "password_value")
private String passwordValue;
}
public enum ExternalLoginType {
ABC;
}
#Column and #Enumerated not works in ExternalLogin entity.
For example in query will be external_login.passwordValue instead of external_login.password_value.
#Enumerated(value = EnumType.STRING) doesn't work too. Hibernate is trying to get int value of filed instead string.
Can anyone help me?
You misuse annotation #Embeddable. See description in oracle docs https://docs.oracle.com/javaee/6/api/javax/persistence/Embeddable.html
Defines a class whose instances are stored as an intrinsic part of an owning entity and share the identity of the entity. Each of the persistent properties or fields of the embedded object is mapped to the database table for the entit
#Embeddable annotation makes sense only for singular assotiation fields. Annotating list fields as #Embeddable is wrong.
Just replace
#Embeddable
public class ExternalLogin {
to
#Entity
public class ExternalLogin {
I had exactly the same issue just now.
The solution for me ended up being adding
#Access(FIELD)
To the Embeddable object.
I want to have hibernate generate some tables with foreign keys and so on. Ill give you an example of the query i want hibernate to generate:
create table RealtimeCost(id INTEGER not null primary key Autoincrement,
mnemonic varchar(50)not null references Exchange(mnemonic),
sid int not null references License(sid),
price numeric(10,2) not null)
so this query should be generated by hibernate via Annotations. The corresponding class to this is:
#Entity
#Table
public class RealtimeCost {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#MapsId("mnemonic")
#JoinColumn(referencedColumnName="sid")
private String mnemonic;
#MapsId("sid")
#JoinColumn(referencedColumnName="sid")
private Integer sid;
#Column
private Double price;
Example for what the mnemonic in RealtimeCost should be mapped to (each mnemonic in RealtimeCost has exactly 1 value in Exchange):
#Entity
#Table
public class Exchange {
#Id
#Column(name="mnemonic")
private String exchange;
#Column
private String description;
As you can see I've tried a bit with the help of the docs, but I was not able to have the foreign keys be generated by hibernate. It would be really kind, if anyone could tell me the needed annotations and values for this class, so i can do it myself for the other classes as well. Also please tell me if i need to change anything in the Exchange class for the mapping to work. Thanks in advance
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "accommodation_type", unique = true, nullable = false)
private AccommodationType accommodationType;
#ManyToOne()creates a relationship according to #JoinColumn()
name in #JoinColumn() is the table name that you want to make a connection.
Then when you create a class that is going to be connected to main class, you first need to give it a table name below #Entity e.g #Table(name="accommodation_types")
Then you create your variable.
//bi-directional many-to-one association to Accommodation
#OneToMany(mappedBy="accommodationType", fetch=FetchType.EAGER)
private List<Accommodation> accommodations;
value of mappedByis the variable name in main class.
I'm not an expert but we let hibernate do all the work with the javax.persistence annotations for joining entities.
#javax.persistence.ManyToOne( fetch = javax.persistence.FetchType.EAGER, optional = true )
#javax.persistence.JoinColumn( name = "VIEWTYPE_ID", nullable = true, unique = false, insertable = true, updatable = true )
private com.company.other.subproject.ViewType viewType;
Maybe this is what you need. Since this let's hibernate care about the tables that have to be created or not and the foreignKeys get created automatically with the dialect of the database you communicate with.
You should set up the association in one entity and use the mappedBy in the other. You don't need #MapsId because you are not using embedded entities (read the docs). Take a look at the #OneToMany and #ManyToOne relationships:
#Entity
#Table
public class RealtimeCost {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#OneToMany
#JoinColumn(name="mnemonic")
private Exchange exchange;
...
}
#Entity
#Table
public class Exchange {
#Id
#Column(name="mnemonic")
private String mnemonic;
#Column
private String description;
#ManyToOne(mappedBy="exchange")
private RealtimeCost realtimeCost;
...
}
Every answer posted here got an upvote from me, because everyone was kinda right, but it was not 100% what i was searching for, yet it helped me solving my problem by myself. For the example i posted, the solution i was seeking is as follows (i also added not nullable):
#Entity
#Table
public class RealtimeCost {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#ManyToOne
#JoinColumn(name = "mnemonic",nullable=false)
private Exchange exchange;
#ManyToOne
#JoinColumn(name = "sid",nullable=false)
private License license;
#Column(nullable=false)
private Double price;
these are the annotations i was seeking for RealtimeCost class. I did not need any special annotations in Exchange class. #Nico answer was closest to what i need, therefore his answer will be accepted