MYSQL stored procedure accessing java object stored as a BLOB - java

I am storing a Java object as an byte in a blob of a table. The java object is customized object. How can I construct the java object and use it in the stored procedure?

Let the class implement java.io.Serializable so that you can get an InputStream of it which you can store in the DB using CallableStatement#setBinaryStream().
That said, this is usually considered a bad design. If the class is actually a Javabean class, you'd better create a table with columns which represents the Javabean properties. E.g. a public class User { private Long id; private String name; private Integer age; } should be mapped to a table like CREATE TABLE user ( id BIGINT AUTO_INCREMENT, name VARCHAR, age INTEGER )
Edit as a reply on your comment: you thus basically want to store an array as binary object. This is a very bad idea. This way you cannot search for the array's data in the database and the database would also not be portable anymore. Just create a new table which represents each of the array items. Add an extra column to it which represents the ID of the parent object (actually, it should be the PK of the table to which the parent object containing the array is been mapped.
Example:
public class Parent {
private Long id;
private String someData;
private List<Child> children;
// Add/generate public getters/setters.
}
public class Child {
private Long id;
private String someData;
// Add/generate public getters/setters.
}
should be mapped to
CREATE TABLE parent (
id BIGINT NOT NULL AUTO_INCREMENT,
someData VARCHAR,
PRIMARY KEY (id)
);
CREATE TABLE child (
id BIGINT NOT NULL AUTO_INCREMENT,
parent_id BIGINT NOT NULL,
someData VARCHAR,
PRIMARY KEY (id),
FOREIGN KEY (parent_id) REFERENCES parent(id)
);
this way you can just select all with help of a JOIN clause. Check the SQL tutorial at w3schools.com and the vendor-specific SQL documentation for examples.

How can I construct the java object and use it in the stored procedure?
This is not possible, at least not with MySQL. Unlike Oracle which supports Java Stored Procedures, MySQL's stored procedure syntax is based on plain ANSI SQL standard. So I don't see how you could construct a Java object from the stream stored in the BLOB. What you can do is acces to the BLOB, but this won't help you much IMHO.
Actually, I think you are totally on the wrong path here, using a BLOB is not the right way to go (at least not here). If you need to persist objects that have a 1:n relation between them, you need to model your database accordingly.
If your Record class has a one to many relation with the User class, which is my understanding, then you have something like this on the Java side:
public class Record {
private Long id;
private User[];
//...
}
Then you need to create two tables at the database level, one for the records and another for the user(s), and model the relation between them using a foreign key (so you can "attach" a user to a record):
CREATE TABLE record
(
record_id INT NOT NULL,
...,
PRIMARY KEY (record_id)
) TYPE = INNODB;
CREATE TABLE user
(
user_id INT NOT NULL,
record_id INT,
...
PRIMARY KEY (user_id),
INDEX (record_id),
FOREIGN KEY (user_id) REFERENCES record (record_id)
) TYPE = INNODB;
Finally, when persisting a Record instance from Java, you'll need to write state in both tables.

Related

Model relationship "User has different Roles per Organization"

I'm trying to achieve the following with JPA: I have Users, Organizations and Roles. A User can have multiple Roles in a given Organization. He can also belong to multiple Organizations, and of course have different Roles per Organization.
Currently I would think that a schema for this should look like this (but also open to alternative aproaches):
CREATE TABLE user
(
id INT NOT NULL AUTO_INCREMENT
);
CREATE TABLE role
(
id INT NOT NULL AUTO_INCREMENT
);
CREATE TABLE organization
(
id INT NOT NULL AUTO_INCREMENT
);
CREATE TABLE `user_and_organization_to_role`
(
`id` INT NOT NULL AUTO_INCREMENT,
`fk_user` INT NOT NULL REFERENCES user (id),
`fk_organization` INT NOT NULL REFERENCES organization (id),
`fk_role` INT NOT NULL REFERENCES role (id),
PRIMARY KEY (`id`),
UNIQUE KEY (`fk_user`, `fk_organization`, `fk_role`)
);
I wouldn't have problems checking roles with native SQL Queries, but I would like to model this in JPA to use the Hibernate Metamodel and Criteria API to implement permission checks.
I thought that something like this would be achievable, even though I'm not 100% sure if I'll reach my goal with Criteria API then:
#Entity
public class Organization {
}
#Entity
public class Role {
}
#Entity
public class User {
private Map<Organization, List<Role>> organizationToRoles;
}
Unfortunately I didn't manage to find a way for the correct annotation, so organizationToRoles is mapped correctly. And even though I would think that is a common problem I didn't find a tutorial that explains how to do this.
Could somebody tell me if such a map is doable with JPA at all, and maybe give an example?
Or if it is not possible to directly have a Map<Organization, List<Role>> organizationToRoles in User, how a mapping could be achived, e.g. with an intermediate Entity that forms the relation between User, Organization and Roles?

Why is a entity - value relationship implemented as a back reference in Spring Data JDBC

In Spring Data JDBC if an entity (e.g. Customer) has a value (e.g. Address) like in the example here the value has a back reference column (column customer in table address) to the entity in the db schema:
CREATE TABLE "customer" (
"id" BIGSERIAL NOT NULL,
"name" VARCHAR(255) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE "address" (
"customer" BIGINT,
"city" VARCHAR(255) NOT NULL
);
The problem with this is that if you use that Address value more than once in one entity or even in different entities you have to define an extra column for each usage. Only the primary id of the entity is stored in these columns and otherwise there is no way to distinguish from which entity it is. In my actual implementation I have five of these columns for the Address value:
"order_address" BIGINT, -- backreference for orderAddress to customer id
"service_address" BIGINT, -- backreference for serviceAddress to customer id
"delivery_address" BIGINT, -- backreference for deliveryAddress to customer id
"installation_address" BIGINT, -- backreference for installationAddress to provider_change id
"account_address" BIGINT, -- backreference for accountAddress to payment id
I understand how it works, but I don't understand the idea behind this back reference implementation. So can someone please shed some light on that issue? Thanks!
As to most good questions there are many sides to the answer.
The historical/symmetry answer
When it comes to references between entities Spring Data JDBC supports 1:1 (the one you ask about) and 1:N (lists, sets and maps).
For the latter anything but a back-reference is just weird/wrong.
And with using a back-reference for 1:1 becomes basically the same, simplifying the code, which is a good thing.
The DML process answer
With the back-reference, the process of inserting and deleting becomes much easier: Insert the aggregate root (customer in your example) first, then all the referenced entities. And it continues to work if those entities have further entities. Deletes work the other way round but are equally straight forward.
The dependency answer
Referenced entities in an aggregate can only exist as part of that aggregate. In that sense they depend on the aggregate root. Without that aggregate root there is no inner entity, while the aggregate root very often might just as well exist without the inner entity. It therefore makes sense, that the inner entity carries the reference.
The ID answer
With this design, the inner entity doesn't even need an id. It's identity is perfectly given by the identity of the aggregate root and in case of multiple one-to-one relationships to the same entity class, the back-reference column used.
Alternatives
All the reasons are more or less based on a single one-to-one relationship. I certainly agree that it looks a little weird for two such relationships to the same class and with 5 as in your example it becomes ridiculous. In such cases you might want to look in alternatives:
Use a map
Instead of modelling your Customer class like this:
class Customer {
#Id
Long id;
String name;
Address orderAddress
Address serviceAddress
Address deliveryAddress
Address installationAddress
Address accountAddress
}
Use a map like this
class Customer {
#Id
Long id;
String name;
Map<String,Address> addresses
}
Which would result in an address table like so
CREATE TABLE "address" (
"customer" BIGINT,
"customer_key" VARCHAR(20). NOT NULL,
"city" VARCHAR(255) NOT NULL
);
You may control the column names with a #MappedCollection annotation and you may add transient getter and setter for individual addresses if you want.
Make it a true value
You refer to Address as a value while I referred to it as an entity. If it should be considered a value I think you should map it as an embedded like so
class Customer {
#Id
Long id;
String name;
#Embedded(onEmpty = USE_NULL, prefix="order_")
Address orderAddress
#Embedded(onEmpty = USE_NULL, prefix="service_")
Address serviceAddress
#Embedded(onEmpty = USE_NULL, prefix="delivery_")
Address deliveryAddress
#Embedded(onEmpty = USE_NULL, prefix="installation_")
Address installationAddress
#Embedded(onEmpty = USE_NULL, prefix="account_")
Address accountAddress
}
This would make the address table superfluous since the data would be folded into the customer table:
CREATE TABLE "customer" (
"id" BIGSERIAL NOT NULL,
"name" VARCHAR(255) NOT NULL,
"order_city" VARCHAR(255) NOT NULL,
"service_city" VARCHAR(255) NOT NULL,
"deliver_city" VARCHAR(255) NOT NULL,
"installation_city" VARCHAR(255) NOT NULL,
"account_city" VARCHAR(255) NOT NULL,
PRIMARY KEY (id)
);
Or is it an aggregate?
But maybe you need addresses on their own, not as part of a customer.
If that is the case an address is its own aggregate.
And references between aggregates should be modelled as ids or AggregateReference. This is described in more detail in Spring Data JDBC, References, and Aggregates

JOOQ: Querying similar tables

I have a situation where I have 2 tables that are almost identical. One table is used for making viewing and editing the data and then the data is published. When the data is published it goes into another table. Essentially WIDGET and PUBLISHED_WIDGET
I have implemented all sorts of custom searching, sorting, filtering and paging queries for 1 table and now I have to implement it for the other. I'm trying to find out a way I can abstract it out and use TableLike<COMMON_WIDGET>.
Example:
create table widget (
id int not null auto_increment,
name varchar(64) not null,
lang varchar(2),
updated_by varchar(64),
updated_on timestamp
//...
);
create table published_widget (
id int not null auto_increment,
name varchar(64) not null,
lang varchar(2),
updated_by varchar(64),
updated_on timestamp
//...
);
I want to be able to do something like this:
public class WidgetDao {
private final TableLike<CommonWidget> table;
public Widget find(String rsql) {
dslContext.selectFrom(table)
.where(table.ID.eq("...").and(table.NAME.eq("...")
// ...
}
Is this possible?
Table mapping
You can use the runtime table mapping feature for this. Choose one of your tables as your "base table" (e.g. WIDGET), and then use a derived configuration with this Settings:
Settings settings = new Settings()
.withRenderMapping(new RenderMapping()
.withSchemata(
new MappedSchema().withInput("MY_SCHEMA")
.withTables(
new MappedTable().withInput("WIDGET")
.withOutput("PUBLISHED_WIDGET"))));
And then:
public Widget find(String rsql) {
// Alternatively, store this derived Configuration in your DAO for caching purposes
dslContext.configuration()
.derive(settings)
.dsl()
.selectFrom(WIDGET)
.where(WIDGET.ID.eq("...").and(WIDGET.NAME.eq("..."))
.fetch();
// ...
}
Such Settings will rename (not alias) the table globally, for a Configuration
Table.rename()
Generated tables have a rename() operation on them, that allows you to do exactly what you want on an ad-hoc basis, not globally. Depending on your use-case, that might be more suitable. Again, this is not the same thing as aliasing (which affects generated SQL).
And again, you'll pick one of your similar/identical tables as your base table, and rename that for your purposes:
public Widget find(String rsql) {
Widget table = WIDGET.rename(PUBLISHED_WIDGET.getQualifiedName());
dslContext.selectFrom(table)
.where(table.ID.eq("...").and(table.NAME.eq("..."))
.fetch();
// ...
}
This method currently (jOOQ 3.14) only exists on generated tables, not on org.jooq.Table, see: https://github.com/jOOQ/jOOQ/issues/5242

Represent sql tables with java classes

i've a problem understanding how to represent a sql table into my java web app and ho to handle the various types of relationship.
Let's suppose to have a department table:
CREATE TABLE IF NOT EXISTS `department` (
`name` varchar(15) NOT NULL,
`number` int(11) NOT NULL,
PRIMARY KEY (`number`),
) ENGINE=InnoDB;
A department has a lot of employees and one employee can work for only one department, so there is a 1:N relationship between department and employees. This could be the employees table:
CREATE TABLE IF NOT EXISTS `employee` (
`first_name` varchar(15) NOT NULL,
`last_name` varchar(15) NOT NULL,
`SSN` char(9) NOT NULL,
`address` varchar(30) DEFAULT NULL,
`gender` char(1) DEFAULT NULL,
`salary` decimal(10,0) DEFAULT NULL,
`N_D` int(11) NOT NULL,
PRIMARY KEY (`SSN`),
FOREIGN KEY `N_D` REFERENCES `department`(`number`),
) ENGINE=InnoDB;
No problem so far but let's go to java now. My application will have a DAO to read the selected elements from the database, maybe two class called DepartmentDAO and EmployeeDAO. My question is how i represent correctly the department entity and employee entity? How should i handle the relationship?
I've seen someone using the array for 1 to many relation and a single object for the opposite case:
public class Department{
private String name;
private Long number;
/*1:N*/
private Employee[] employees;
/*getter and setter*/
}
The employee class:
public class Employee{
private String firstName;
private String lastName;
private String SSN;
private String address;
private String gender;
private int salary;
/*N:1*/
private Department department;
/*getter and setter*/
}
It seems okay but how do i read nested objects? In the employee case i could use the join in my query for reading two object but in the other case i've got an array.
I want, for example, visualize the number of employees for a certain department. When i read the department object i should also read N employee objects and the by employees.length i could get the number. Isn't it a bit too expensive? It would be wrong put another attribute in my department class (private int numberOfEmployees;) and read it by using COUNT in sql?
Thanks in advance for the help.
If I got it right, you want to count the employees foreach department, or not?
If so, I recommend using the dao pattern.
In additon to the dao pattern, you can use a Key : Value List or Map like the Hashmap.
The Map should contain as Key the specific department and as value the employee. Besides, you have to synchronize the database and the Java Objects to add pairs to the map.
Summarized, you need to create a Data Management Class which contains a List or Map with a key (department) and a value (employee).
Besides, it must be able to do transactions with the database to synchronize the data.
Therefore, you can use the dao pattern and a HashMap, references below.
I do not know if this is good practicse, but it will work.
Dao Pattern
HashMap
EDIT: As I read your question again, the HashMap should be in your department class, but you can still use the dao pattern for synchronizing and data management.

Entity class with a composite primary key doesn't have getter and setter

I have an entity class userdetails which has the username, userid (numeric) and password fields, with username and userid forming a composite primary key. This is negotiable, and possibly unimportant to the main problem.
I have another class, connectiontable, which has userid as the primary key. The sql code used to generate the relevant tables is as follows:
create table usertable
(
userid int NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),
username varchar(128) NOT NULL UNIQUE,
password varchar(128) NOT NULL,
CONSTRAINT USER_PK PRIMARY KEY(username, userid)
);
That's the sql code for usertable. The following is for connectiontable
create table connectiontable
(
userid int not null,
username varchar(128) not null,
connections varchar(32670) not null,
CONSTRAINT CONNECTION_PK PRIMARY KEY(username, userid),
CONSTRAINT CONNECTION_FK FOREIGN KEY(username,userid) REFERENCES usertable(username,userid)
);
There are a bunch of other things in connectiontable, but those are irrelevant. I use netbeans 7.2.1 and Jave EE6. I use the 'create entities from database entries' but for some reason, I don't have a getter and setter for either userid or username. They are in connectiontablePK, but I can't seem to make use of that. For example, when I generate the jsf pages, I want to be able to do something like:
Connectiontable con = new Connectiontable();
con.getUsername();
But it complains because it can't find that method in connectiontable.java.
Can anyone advise me why this is the case, and how I can solve it? Thank you.
... You're not posting the Java code, which I suspect would help but:
Anytime in JPA when you have a composite primary key, you have to have an 'embedded' primary-key class. I suspect you have a class definition similar to the following:
#Embeddable
public class UserNameId {
private int userid;
private String username;
}
And then usertable and connectiontable both contain the following (or similar):
#Embedded
#Id
private UserNameId userNameId;
... So you should expect a getter/setter for userNameId, but not the embedded fields, like you expect.

Categories