Mapping Linking Table with 3 PK's in Hibernate - java

right now I'm having trouble mapping a linking table with Hibernate.
First of all I want to explain what I want to map:
I have 3 tables: Product , DocumentType, Language.
One Product can have each DocumentType (at the moment we have 7 DocumentTypes) in each specific Language (at the moment we have 3 Languages)
That means product "1" can have DocumentType "A" in language "EN", "ES" and "FR".
I created a linking table with 3 foreign keys which are also composite primary key.
Here is how my sql looks like.
CREATE TABLE Person(
id int PRIMARY KEY AUTO_INCREMENT,
name varchar(255)
);
CREATE TABLE DocumentType(
id int PRIMARY KEY AUTO_INCREMENT,
name varchar(255),
key varchar(255)
);
CREATE TABLE Language(
id int PRIMARY KEY AUTO_INCREMENT,
name varchar(255),
code varchar(2)
);
CREATE TABLE Person_DocumentType_Language(
person_id int NOT NULL,
doc_id int NOT NULL,
lang_id NOT NULL,
FOREIGN KEY(person_id)
REFERENCES Person(id),
FOREIGN KEY(doc_id)
REFERENCES DocumentType(id),
FOREIGN KEY(lang_id)
REFERENCES Language(id),
PRIMARY KEY(person_id, doc_id, lang_id)
);
With the last linking table I could tell which Person has which DocumentTypes and in which Languages.
I'm mostly interested in the information which DocumentType has which Language for one Person.
Say I'm Person A. Now I want to know which DocumentTypes I have with which Languages. In SQL it would look like this I think:
Select doc_id, lang_id from Person_DocumentType_Language where person_id=1
Does that make sense? And how could I map this in Hibernate?

One approach is have a Map from DocumentType to Language. I'm a bit rusty on the exact annotation, but here is a start:
public class Person {
#Id
public int id;
#OneToMany(targetEntity=Language.class)
#MapKeyClass(Integer.class)
#CollectionTable(name="Person_DocumentType_Language")
#MapKeyColumn(name="doc_id")
public Map<DocumentType,Language> docTypeLang;
}

Related

How to get n:m tables?

I have a spring-boot application with a MySql database. I have a many-to-many relationship between a pizza table and a topping table so I've made an extra table where I store these relationships. The tables:
CREATE TABLE topping (
id SERIAL PRIMARY KEY,
topping_name VARCHAR(64) NOT NULL,
price INT NOT NULL,
spicy bool NOT NULL
);
CREATE TABLE pizza (
id SERIAL PRIMARY KEY,
pizza_name VARCHAR(64) NOT NULL
);
CREATE TABLE pizza_with_topping (
pizza_id BIGINT UNSIGNED NOT NULL,
topping_id BIGINT UNSIGNED NOT NULL,
CONSTRAINT pizza_with_topping_ibfk_1
FOREIGN KEY(pizza_id)
REFERENCES pizza(id),
CONSTRAINT pizza_with_topping_ibfk_2
FOREIGN KEY(topping_id)
REFERENCES topping(id)
);
In spring-boot I found that I have to extend the CrudRepository interface and I can call the findAll() method from this to get the contents of a table. At the momment I get the contents of all 3 tables like so:
Iterable<Pizza> pizzasInDb = pizzaRepository.findAll();
Iterable<Topping> toppingsInDb = toppingRepository.findAll();
Iterable<PizzaWithTopping> pizzaToppingConnectionTable = pizzaWithToppingRepository.findAll();
After this based on these 3 tables I manually create objects that contain both the pizza's name and it's toppings. Since I have set foreign keys in pizza_with_topping table I was wondering if there is a better way to get this model? Maybe with the call of built-in functions that automatically makes this model object for me based on the foreign keys.
Yes, there is. You can model your domain with many-to-many relationships using JPA. If you are using annotation this cam be achieve using #ManyToMany
There is an example here

Accurate tables for Database normalization

I am thinking on how could I normalize as accurate as possible my tables in my database.
I have to develop a monitoring system where the system should analyse all the outgoing messages(Emails, SMS..) send to customers and their related feedback(status(0,1 or more)).
It means that for 1 outgoing message(With for ex MAILID: 123) I can have multiple different feedbacks(SENT, NOT DELIVERED, DELIVERED, CLICKED, OPENED...) received at different time intervals. For some feedback received I must retrieve the information of what the Email Service provider did in term of "Action". Did they send the email again to the customer?, did they manage to resolve the servers issues if not delivered? etc..
EDIT: I am sorry in fact my MAIL ID columns are all VARCHARS (Java Strings). Long story short, In fact I have to process XML files and unmarshal them to Java Object and persist them into my Mysql dataBase where MAIL ID is in the form of BMM1EP_34022503920_1200180009
To clarify I thought I should have 4 main tables.
Table SentMessages with columns:
MailId VARCHAR primary key(not null)
Form_Name varchar(50)
Language varchar(10)
OutPut_Mode varchar(10)
Table FeedBackMessages with columns:
Id INT AutoIncrement primary key (not null)
MailId VARCHAR
Return_Date DATE
Return_Time DATETIME
FOREIGN KEY (MailId) REFERENCES SentMessages (MailId)
Table Status with columns:
Id Int AutoIncrement primary key (not null)
MailId VARCHAR
Status VARCHAR(50)
FOREIGN KEY (MailId) REFERENCES SentMessages(MailId)
Table Action with columns:
Id Int AutoIncrement primary key(not null)
ActionTaken VARCHAR(100)
MailId VARCHAR
FOREIGN KEY (MailId) REFERNCES Status(Id)
Is my design bad? Help will be highly appreciated as I really struggle it is my first time designing a real database for a concrete project. Thanks to all of you!
It helps if you use a semi-formal natural language to define your business domain. As I understand it:
There are 0..n email messages
Each email message will have 0..n feedback items
Each feedback item has 1 status, and may have additional action information.
If that's accurate, the design would be something like:
Table SentMessages with columns:
MailId varchar primary key(not null)
Form_Name varchar(50)
Language varchar(10)
OutPut_Mode varchar(10)
Table FeedBackMessages with columns:
Id INT AutoIncrement primary key (not null)
MailId varchar
Return_Date DATE
Return_Time DATETIME
Status VARCHAR(50)
ActionTaken VARCHAR(100)
FOREIGN KEY (MailId) REFERENCES SentMessages (MailId)

jpa one to one relationship using mysql

Here is my tables definition
CREATE TABLE IF NOT EXISTS `store` (
`store_id` INT NOT NULL AUTO_INCREMENT,
`store_name` VARCHAR(1024) NOT NULL,
`store_user` INT NOT NULL,
`store_address` INT NOT NULL,
`store_type` INT NOT NULL,
`created_date` DATETIME NOT NULL,
`updated_date` DATETIME NOT NULL,
PRIMARY KEY (`store_id`)
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `store_address` (
`address_id` INT NOT NULL AUTO_INCREMENT,
`address_line_1` VARCHAR(1024) NOT NULL,
`address_line_2` VARCHAR(1024) NOT NULL,
`address_line_3` VARCHAR(1024) NULL,
`city` VARCHAR(45) NOT NULL,
`locality` VARCHAR(100) NOT NULL,
`pincode` CHAR(6) NOT NULL,
`latitude` DECIMAL(8,6) NULL,
`longitude` DECIMAL(9,6) NULL,
`state` VARCHAR(45) NOT NULL,
`created_date` DATETIME NOT NULL,
`updated_date` DATETIME NOT NULL,
PRIMARY KEY (`address_id`),
CONSTRAINT `FK_STR_STR_ADR`
FOREIGN KEY (`address_id`)
REFERENCES `store` (`store_address`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
I am trying to have a 1-1 mapping between store and its address. Considering the DDL is ok, while generating JPA entities Store.java look like this:
#Entity
#Table(name="store")
public class Store
{
#Basic
#Column(name="created_date", nullable=false)
private Date createdDate;
#OneToOne(fetch=FetchType.LAZY, mappedBy="store", cascade=CascadeType.MERGE)
private StoreAddress storeAddress;
#Basic
#Column(name="store_address", columnDefinition="INT")
private int storeAddress2;
/////
Why is there a field storeAddress2 in Store.java? I think this is failing my insertion of a store. Any help?
Considering the DDL is ok [...]
The DDL is not OK, it is erroneous. As the tables are presently structured, the foreign key constraint is backward. store_address.address_id is the referenced key; the constrained column -- that is, the foreign key column -- should be store.store_address.
Moreover, be aware that putting the address into its own table and establishing a NOT NULL foreign key referencing it means that every store must have an address recorded, yet a store address does not have to correspond to any store. If you want the address to be optional then make store.store_address nullable, though that still permits addresses to exist that do not correspond to a store.
Alternatively, even though JPA prefers a forward mapping from parent to child such as you have presented, it is possible to map it in the other direction, so that store addresses cannot exist in the DB without a corresponding store, but stores do not have to have addresses recorded. In the DDL, that would correspond to deleting store.store_address, and creating store_address.store_id as a foreign key referencing store.store_id.
Update:
Here is some DDL to clarify my comments about the FK constraint. This is how an FK relationship between store and store_address should be written, given the column definitions as presented in the question:
CREATE TABLE IF NOT EXISTS `store` (
`store_id` INT NOT NULL AUTO_INCREMENT,
`store_address` INT NOT NULL,
-- ...
PRIMARY KEY (`store_id`),
CONSTRAINT `FK_STR_STR_ADR`
FOREIGN KEY (`store_address`)
REFERENCES `store_address` (`address_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION
)
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `store_address` (
`address_id` INT NOT NULL AUTO_INCREMENT,
-- ...
PRIMARY KEY (`address_id`)
-- the FK constraint does NOT go here
)
ENGINE = InnoDB;
Note also that as I already wrote, this does not enforce a 1-1 relationship in the DB. If you want that then you could put a UNIQUE constraint on store.store_address, but it might be better to instead link the PKs of store and store_address. That way you can also prevent orphan store_address rows from being allowed. That could look like this:
CREATE TABLE IF NOT EXISTS `store` (
`store_id` INT NOT NULL AUTO_INCREMENT,
-- ... no store_address ...
PRIMARY KEY (`store_id`)
-- ... no FK constraint here ...
)
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `store_address` (
-- addresses do not have independent IDs:
`store_id` INT NOT NULL,
-- ...
PRIMARY KEY (`store_id`),
CONSTRAINT `FK_STR_STR_ADR`
FOREIGN KEY (`store_id`)
REFERENCES `store` (`store_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION
)
ENGINE = InnoDB;
That does permit a store to exist without a corresponding address, which may be sensible, even though you say you don't want that.
Really, though, if a store must not exist without exactly one corresponding address, and a store address must not exist without a store, then why are you mapping these as separate tables? It gains you nothing except, maybe, less manual adjustment to automatically-generated entity classes. It's definitely a loss in the performance and DB complexity arenas.
Note, too, that JPA has annotations for mapping two closely-associated entities to the same table, if you insist that the addresses should be separate entities from their associated stores. Look into the #Embeddable and related annotations.

create a tree structure in java using hierarchical data from database

I have this problem at hand which is as follows :
There is a many-to-many relationship between User & Group.The back-end has tables for the respective entity classes as well as an intersection table User_Groups which stores information about the association of a user to groups.The Groups table has two columns which are relevant to the problem at hand.The Structure of group table is as follows:
Table name - GROUP
CREATE TABLE IF NOT EXISTS
GROUP
(
GROUP_ID INT NOT NULL AUTO_INCREMENT ,
NAME VARCHAR(50) NULL ,
DESCRIPTION VARCHAR(50) NULL ,
CREATED_DATE DATE NULL ,
CREATED_BY VARCHAR(50) NULL ,
MODIFIED_DATE DATE NULL ,
MODIFIED_BY VARCHAR(50) NULL ,
GROUP_TYPE_ID INT NULL ,
PARENT_GROUP_ID INT NULL ,
PRIMARY KEY (GROUP_ID) ,
INDEX fk_groupTypeId_idx (GROUP_TYPE_ID ASC) ,
CONSTRAINT fk_groupTypeId FOREIGN KEY (GROUP_TYPE_ID )
REFERENCES efc_group_type (GROUP_TYPE_ID )
ON DELETE NO ACTION
ON UPDATE NO ACTION);
------------------------------------------------------------------------------------------
Table name - USER_GROUPS
CREATE TABLE IF NOT EXISTS
EFC_USER_GROUPS
(
USER_ID int(11) NOT NULL,
GROUP_ID int(11) NOT NULL,
CREATED_DATE date DEFAULT NULL,
PRIMARY KEY (USER_ID,GROUP_ID),
KEY FK_USERID_idx (USER_ID),
KEY FK_GROUPID_idx (GROUP_ID),
CONSTRAINT FK_GROUPID_USERGROUPS FOREIGN KEY (GROUP_ID)
REFERENCES efc_group (GROUP_ID),
CONSTRAINT FK_USERID_USERGROUPS FOREIGN KEY (USER_ID)
REFERENCES efc_user (USER_ID));
The parent_group_id is basically acting as a foreign column to the group_id. A group can have sub-groups and hence the need to store the parent_group_Id. For each sub-group added, we store the parent_group_id for that group under which sub-group was added. Now that you have some idea about the data model, I'll illustrate what my problem is:
I am trying to construct a tree like structure for the parent-child relationship between groups & sub-groups for a certain user. So corresponding to a certain user Id, I am able to get the groups that he is part of from the user_groups table.Then I am able to filter the groups into two lists, one representing the parent nodes and the other has all child nodes. Now the hierarchy between groups is stored in the group table. I am not able to figure out how to implement that in java. I already have the list with me but in that list each group can have parents above it and also children below it. I am not able to understand how to build the top to bottom hierarchy. My sole purpose is to build that XML constituting the parent-nodes down to last child node and send it to the front-end.
P.S : I have googled quite a bit.I am running short of ideas :(. Please help me

Mahout and custom table for data model

The documentation says that the table of ratings should look like this:
CREATE TABLE taste_preferences (
user_id BIGINT NOT NULL,
item_id BIGINT NOT NULL,
preference REAL NOT NULL,
PRIMARY KEY (user_id, item_id)
);
However, in my implementation table of ratings is as follows:
CREATE TABLE taste_preferences (
profile_id BIGINT NOT NULL,
event_id BIGINT NOT NULL,
status_id BIGINT NOT NULL,
PRIMARY KEY (user_id, item_id)
);
Where the grade is in the form status_id (go, no go, maybe I'll go).
The users table as follows:
CREATE TABLE user (
profile_id_1 BIGINT NOT NULL,
profile_id_2 BIGINT NOT NULL,
profile_id_3 BIGINT NOT NULL,
...
);
A user can have multiple profiles, I need to compare these data to users.
I need to write its own implementation of data model? Which way do I see, that would solve this problem? Thanks!
You don't have rating data here, in any form. So, you can't use ratings in recommendations. That's fine; you just have "boolean" data.
Or, you're saying you need to use status but I'm not clear how you want to use it.
You can certainly use your taste_preferences table. Just use MySQLBooleanPrefJDBCDataModel or similar. The user table is irrelevant.

Categories

Resources