ORMlite + MySQL Foreign Key Binding - java

How do I create auto delete cascade using ORMLite? I am using ormlite-core and omlite-jdbc version 4.8. I tried
public class Account {
// for QueryBuilder to be able to find the fields
public static final String NAME_FIELD_NAME = "name";
public static final String PASSWORD_FIELD_NAME = "passwd";
#DatabaseField(generatedId = true)
private int id;
#DatabaseField(columnName = NAME_FIELD_NAME, canBeNull = false)
private String name;
#DatabaseField(columnName = PASSWORD_FIELD_NAME)
private String password;
}
and another class
#DatabaseTable(tableName = "orders")
public class Order {
public static final String ACCOUNT_ID_FIELD_NAME = "account_id";
#DatabaseField(generatedId = true)
private int id;
#DatabaseField(foreign = true, columnName = ACCOUNT_ID_FIELD_NAME,
canBeNull = false,index = true, foreignAutoRefresh = true,
columnDefinition = "integer references document(id) on delete cascade")
private Account account;
#DatabaseField
private int itemNumber;
#DatabaseField
private int quantity;
#DatabaseField
private float price;
}
But When I delete the parent key record, no exception is being thrown and also, if try to insert records in order table with foreign key values which are not defined in the Account table, no exception is being thrown and the records get created and inserted in database.

But When i delete the parent key record , no exception is being thrown and also , if try to insert records in order table with foreign key values which are not defined in the Account table, no exception is being thrown and the records get created and inserted in database .
Stupid answer but shouldn't the column definition be:
integer references account(id) on delete cascade
I assume that the Account table is named account and not document. Otherwise your SQL looks good.
I would take a look at the schema on the MySQL side to make sure that it matches what you are expecting. I'd also try some inserts from the MySQL command line to see if you can figure out what is going on outside of ORMLite.
Hope this helps.

Related

TypeMismatchException on fetching the table data by Hibernate Session.get() method

In a application, having a database table CUSTOMERS defined as:
create table CUSTOMERS (
ID varchar(10),
CODE varchar(10),
CID varchar(10),
SID varchar(10),
FNAME varchar(50),
LNAME varchar(50),
constraint PK_CUSTOMERS primary key (ID, CODE, CID, SID)
);
and the Entity classes are created to populate the data as
#Embeddable
public class CustKey implements Serializable , Cloneable{
#Transient
private static final long serialVersionUID = 1L;
#Column(name = "ID", nullable = false)
private String id;
#Column(name = "CODE", nullable = false)
private String code;
#Column(name = "CID", nullable = false)
private String cid;
#Column(name = "SID", nullable = false)
private String sid;
public boolean equals(Object o){
return id.equals(o.getId()) && ...;
}
public int hashcode(){
return id.hashcode() & ...;
}
}
#Entity
#Table(name = "CUSTOMERS")
public class CustProfileWrapper implements Serializable,Cloneable {
#Transient
private static final long serialVersionUID = 1L;
#EmbeddedId
private CustKey custKey;
#Column(name = "FNAME")
private String fname;
#Column(name = "LNAME")
private String lname;
}
The records are populated without an issue.
But the Entity classes are move to other project (but keeping the same package name as before) due to some rewrite of the code/project. but on fetching the data by Hibernate Session as
Object object = session.get(CustProfileWrapper.class, custProfileWrapper.getCustKey(), LockMode.NONE);
getting the error
org.hibernate.TypeMismatchException: Provided id of the wrong type for class CustProfileWrapper. Expected: class com.db.CustProfileWrapper, got class com.db.CustProfileWrapper
However, able to get the record when using the parametrized query as
SQLQuery query = session.createSQLQuery("SELECT * FROM CUSTOMERS WHERE ID = ? "
+ " AND CODE = ? AND CID = ? AND SID = ? ");
query.addEntity(CustProfileWrapper.class);
query.setParameter(0, "101");
...
object = query.list();
But it's a low level code when using the query, and we should use the
better way like get() method.
Any help/hint will be appreciated!!
Full stack trace of the error:
After so much investigation, found the culprit spring-boot-devtools dependency, as explained here:
I was getting this problem after adding a dependency to
spring-boot-devtools in my Springboot project. I removed the
dependency and the problem went away. My best guess at this point is
that spring-boot-devtools brings in a new classloader and that causes
the issue of class casting problems between different classloaders in
certain cases where the new classloader is not being used by some
threads.
Reference: A dozer map exception related to Spring boot devtools
Refs: ClassCastException when casting to the same class

How in JPA make a save updates a record and prevent from unique key violation?

How to check if a record exists in database before a save() because in my case, I have a field (not an #Id) that is a unique key. In my website, I have a form in 3 steps :
Step 1 : after setting firstname, lastname, the user clicks on "next" that will make a save() = Insert because the user is a new one in database. the is a column in database called "FirstnameAndLastname" which is the unique key
Step 2 : the user is asked to fill his email, and click on "next" : it's the same first save() and here is the error saying that a unique constraints violation happends !
And I understand it, as from step 1, the unique key is set, and in step 2 I try to write again with the same unique, so how to make the seconde save() to be an update ??
here is my entity :
#Entity
#Table(name = "student")
public class Student implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "firstname")
private String firstname;
#Column(name = "lastname")
private String lastname;
#Column(name = "firstAndLastname")
private String firstLastname;
// other columns + setter and getters etc
And here is my save()
#Override
public Student save(Student newStudent) {
return studentRepository.save(newStudent);
}
#Override
#Transactional
public void save(List<Student> students, String firstname, String lastname) {
students.forEach(newStudent-> {
newStudent.setFirstLastname(firstname+lastname); // concatenation to make the unique key
save(newStudent);
});
}
I saw many answers saying that we should first fetch (find) student before saving, how to make it ?

ForeignCollection throws SQLException on iterating using streams

I have three entity classes: PlayerData, IpData, and TwinData.
Both TwinData and IpData refer to PlayerData with a foreign key.
Here is the code:
#DatabaseTable
public class PlayerData {
#DatabaseField(generatedId = true)
private int id;
#DatabaseField
private UUID uuid;
#ForeignCollectionField
private ForeignCollection<IpData> ips;
#ForeignCollectionField
private ForeignCollection<TwinData> twins;
// Getters and setters...
}
#DatabaseTable
public class IpData {
#DatabaseField(generatedId = true)
private int id;
#DatabaseField(foreign = true)
private PlayerData playerData;
#DatabaseField
private Date firstUsage;
#DatabaseField
private String address;
// Getters and setters...
}
#DatabaseTable
public class TwinData {
#DatabaseField(generatedId = true)
private int id;
#DatabaseField(foreign = true)
private PlayerData mainPlayer;
#DatabaseField
private boolean adminNoticed;
#DatabaseField
private UUID uuid;
// Getters and setters...
}
When I try to iterate over PlayerData.ips with streams, I get SQLException [SQLITE_ERROR] SQL error or missing database (no such column: playerData_id). Tables are auto-generated with TableUtils.createIfNotExists().
This is the code that throws that exception:
// playerData is retrieved from Dao<PlayerData, Integer>
playerData.getIps().stream().noneMatch(ip -> ip.getAddress().equals(playerIp))
I just don't really get why it attempts to select playerData_id column.
Should I manually create database tables for TwinData and IpData with playerData_id column? Haven't tried this yet, but I don't think it would help.
When I try to iterate over PlayerData.ips with streams, I get SQLException[SQLITE_ERROR] SQL error or missing database (no such column: playerData_id). Tables are auto-generated with TableUtils.createIfNotExists().
You will get that error if playerData_id is not a field in the table. I'm surprised that TableUtils.createIfNotExists() did not create a field playerData_id in the IpData table. I suspect that the tables existed already and you are not using ORMLite generated schema.
By default when ORMLite sees a foreign = true field, it will store the id of that type in the entity in question. See the foreign fields documentation. If your schema is defining the relationship between the entities differently, for example with another table to define the relationship, then you will need to setup that entity by yourself and query it using the DAO for that entity.
You maybe should look at the foreign object example for more information.
Hope this helps.

Hibernate session.get() is always returning null

#Entity
#Table(name = "T019_STAFF_PROFILE")
public class UserDetails implements Serializable
{
private static final long serialVersionUID = -723583058586873479L;
#Id
#Column(name = "STAFF_ID", columnDefinition="CHAR(8)")
private String loginId;
#Column(name = "PASSWORD", columnDefinition="CHAR(8)")
private String password;
#Column(name = "FIRST_NAM")
private String firstName;
#Column(name = "LAST_NAM")
private String lastName;
#Column(name = "BUS_OG_CD" , columnDefinition="CHAR(3)")
private String profile;
public UserDetails getLoginDetails(String loginId)
{
UserDetails object =(UserDetails)sessionFactory.getCurrentSession().get(UserDetails.class, loginId);
return object;
}
Check the database to see if the value really exists in the database.
SELECT * FROM T019_STAFF_PROFILE WHERE STAFF_ID = <the value of **loginId**>
For Time being, created a temp user with exactly 8 chars and then tried to access the same user through hibernate. I was able to fetch the record.
#Id
#Column(name = "STAFF_ID", columnDefinition="CHAR(8)")
private String loginId;
This is my column definition. Is there any thing that i need to declare?
Found something interesting. Correct me if the approach is wrong.
Since my db column is declared as CHAR(8), to hibernate, i should always pass 8 char to get the results.
So, if your STAFF_ID is 3 chars, append 5 empty chars and the pass it to hibernate which will fetch your record.
Any thoughts?
Session.get(Class clazz, Serializable id)
Return the persistent instance of the given entity class with the
given identifier, or null if there is no such persistent instance. (If
the instance is already associated with the session, return that
instance. This method never returns an uninitialized instance.)
So check if data exists in your database or not.

JPA OneToMany bi-directional

I know that there is many question about it but i can not find a good answered for my problem .
I am using Jboss as 7, Spring and Hibernate (4) as JPA 2.0 provider so i have got simple #OneToMany bi-directional relationship :
I have got super class person like that:
#MappedSuperclass
#Inheritance(strategy=InheritanceType.JOINED)
public abstract class Person {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#NotNull
#Size(min = 1, max = 25)
#Pattern(regexp = "[A-Za-z ]*", message = "must contain only letters and spaces")
private String name;
public Person(String name) {
super();
this.name = name;
}
And class Member:
#Entity
#Table(uniqueConstraints = #UniqueConstraint(columnNames = "email"))
public class Member extends Person implements Serializable
{
/** Default value included to remove warning. Remove or modify at will. **/
private static final long serialVersionUID = 1L;
#NotNull
#NotEmpty
#Email
private String email;
#NotNull
#Size(min = 10, max = 12)
#Digits(fraction = 0, integer = 12)
#Column(name = "phone_number")
private String phoneNumber;
#OneToMany(cascade=CascadeType.ALL , mappedBy="member" , fetch=FetchType.EAGER)
private List<Order> orders;
And also class Order:
#Entity
public class Order {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
private float price;
#ManyToOne(optional=false)
private Member member;
private String name;
So i think that it is a good configuration, but i test this application in HSQL in memory and i have got error :
Hibernate: alter table Order drop constraint FK48E972E548C740B
2012-09-20 16:25:37 org.hibernate.tool.hbm2ddl.SchemaExport perform
ERROR: HHH000389: Unsuccessful: alter table Order drop constraint FK48E972E548C740B
2012-09-20 16:25:37 org.hibernate.tool.hbm2ddl.SchemaExport perform
ERROR: Blad skladniowy w wyrazeniu SQL "ALTER TABLE ORDER[*] DROP CONSTRAINT FK48E972E548C740B "; oczekiwano "identifier"
Syntax error in SQL statement "ALTER TABLE ORDER[*] DROP CONSTRAINT FK48E972E548C740B "; expected "identifier"; SQL statement:
alter table Order drop constraint FK48E972E548C740B [42001-165]
And also :
Syntax error in SQL statement "CREATE TABLE ORDER[*] (ID INTEGER GENERATED BY DEFAULT AS IDENTITY, NAME VARCHAR(255), PRICE FLOAT NOT NULL, MEMBER_ID BIGINT NOT NULL, PRIMARY KEY (ID)) "; expected "identifier"; SQL statement:
And my JUnit test failed i dont know what is wrong with this configuration ...
this is my simply junit :
#Test
public void testInsertWithOrder(){
Order order = new Order(20.0f, "first stuff");
Order order2 = new Order(40.0f, "secondary stuff");
List<Order> orders = new ArrayList<Order>();
orders.add(order2);
orders.add(order);
Member member = new Member("Member name", "member23#gmail.com", "2125552141", orders);
memberDao.register(member);
List<Member> members = memberDao.findAllOrderedByName();
Assert.assertNotNull(members);
Assert.assertEquals(1, members.size());
}
Change table name from 'order' to something different, like PersonOrder
In your member in Order Class, there are missing #JoinColumn annotation. Try as below.
#ManyToOne(optional=false)
#JoinColumn(name = "memberId", referencedColumnName = "id")
private Member member;
#CycDemo
I am just figure it out and in my constuctor i now have got :
#OneToMany(cascade=CascadeType.ALL , mappedBy="member" , fetch=FetchType.EAGER)
private List<UOrder> orders = new ArrayList<UOrder>();
public Member(String name, String email, String phoneNumber ,List<UOrder> orders) {
super(name);
this.orders = orders;
this.email = email;
for(UOrder o : orders){
o.setMember(this);
}
this.orders = orders;
}
Ant this is it what i need :)))

Categories

Resources