JPA Relation or Secondary Table - jpa

I am reengineering one of my project with JPA which was initially on iBatis.
public class Entity{
//ids and other stuff
String locale;
String text;
}
I was storing locale and text into separate table, which can be achieved via secondary table in JPA.
I am not able to create secondary table with its own ids besides Join
id?
how can I achieve it? If possible then it raises the following
question:
how would I retrieve it back if I create an entity object with locale set to user settings

See,
http://en.wikibooks.org/wiki/Java_Persistence/Tables#Multiple_tables
Otherwise include your exact schema and model and issue.

Related

JPA and PostgreSQL with GenerationType.IDENTITY

I have a question about Postgres and GenerationType.Identity vs Sequence
In this example...
#Id
#SequenceGenerator(name="mytable_id_seq",
sequenceName="mytable_id_seq",
allocationSize=1)
#GeneratedValue(strategy = GenerationType.SEQUENCE,
generator="mytable_id_seq")
I understand that I am specifying a Postgres sequence to use via annotations.
However, I have an id column defined with the 'serial' type, I have read that I can simply use GenerationType.IDENTITY and it will automatically generate a db sequence and use it to auto increment.
If that's the case, I don't see an advantage to using the SEQUENCE annotations unless you are using an integer for an id or have some specific reason to use another sequence you have created. IDENTITY is alot less code and potentially makes it portable across databases.
Is there something I'm missing?
Thanks in advance for the feedback.
If you have a column of type SERIAL, it will be sufficient to annotate your id field with:
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
This is telling Hibernate that the database will be looking after the generation of the id column. How the database implements the auto-generation is vendor specific and can be considered "transparent" to Hibernate. Hibernate just needs to know that after the row is inserted, there will be an id value for that row that it can retrieve somehow.
If using GenerationType.SEQUENCE, you are telling Hibernate that the database is not automatically populating the id column. Instead, it is Hibernate's responsibility to get the next sequence value from the specified sequence and use that as the id value when inserting the row. So Hibernate is generating and inserting the id.
In the case of Postgres, it happens that defining a SERIAL column is implemented by creating a sequence and using it as a default column value. But it is the database that is populating the id field so using GenerationType.IDENTITY tells Hibernate that the database is handling id generation.
These references may help:
http://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#identifiers-generators
https://www.postgresql.org/docs/8.1/static/datatype.html#DATATYPE-SERIAL
From "Pro JPA2" book:
"Another difference, hinted at earlier, between using IDENTITY and other id generation strategies is that the identifier will not be accessible until after the insert has occurred. Although no guarantee is made about the accessibility of the identifier before the transaction has completed, it is at least possible for other types of generation to eagerly allocate the identifier. But when using identity, it is the action of inserting that causes the identifier to be generated. It would be impossible for the identifier to be available before the entity is inserted into the database, and because insertion of entities is most often deferred until commit time, the identifier would not be available until after the transaction has been committed."
I think it can be helpful if you are using the same sequence for more than one table (for example you want a unique identifier for many types of bills) ... also If you want to keep track of the sequence away from the auto generated key
You can find here the solution of updating the PostgreSQL table creation accordingly, in order to work with the GenerationType.IDENTITY option.

How to optionally persist secondary table in Eclipselink

I am working with Eclipselink and having issue with using secondary table.
I have two tables as below.
Student with columns student_id(Primary Key), student_name etc.
Registration with columns student_id(FK relationship with Student table), course_name (with not null constraint) etc.
The requirement is student may or may not have registration. If student has registration, the data should be persisted to Registration table as well. Otherwise only Student table should be persisted.
My code snippet is as below.
Student.java
------------
#Entity
#Table(name = "STUDENT")
#SecondaryTable(name = "REGISTRATION")
#Id
#Column(name = "STUDENT_ID")
private long studentId;
#Basic(optional=true)
#Column(name = "COURSE_NAME", table = "REGISTRATION")
private String courseName;
I tried the following scenarios.
1. Student with registration - Working fine. Data is added to both Student and Registration tables
2. Student without registration - Getting error such as 'COURSE_NAME' cannot be null.
Is there a way to prevent persisting into secondary table?
Any help is much appreciated.
Thanks!!!
As #Eelke states, the best solution is to define two classes and a OneToOne relationship.
Potentially you could also use inheritance, having a Student and a RegisteredStudent that adds the additional table. But the relationship is a much better design.
It‘s possible using a DescriptorEventListener. The aboutToInsert and aboutToUpdate callbacks have access to the DatabaseCalls and may even remove the statements hitting the secondary table.
Register the DescriptorEventListener with the ClassDescriptor of the entity. For registration use a DescriptorCustomizer specified in a Customizer annotation at the entity.
However, you will not succeed fetching the entities back again later on. EclipseLink uses inner joins when selecting from the secondary table, so that the row of the primary table will be gone in the results.

Entity Framework : map duplicate tables to single entity at runtime?

I have a legacy database with a particular table -- I will call it ItemTable -- that can have billions of rows of data. To overcome database restrictions, we have decided to split the table into "silos" whenever the number of rows reaches 100,000,000. So, ItemTable will exist, then a procedure will run in the middle of the night to check the number of rows. If numberOfRows is > 100,000,000 then silo1_ItemTable will be created. Any Items added to the database from now on will be added to silo1_ItemTable (until it grows to big, then silo2_ItemTable will exist...)
ItemTable and silo1_ItemTable can be mapped to the same Item entity because the table structures are identical, but I am not sure how to set this mapping up at runtime, or how to specify the table name for my queries. All inserts should be added to the latest siloX_ItemTable, and all Reads should be from a specified siloX_ItemTable.
I have a separate siloTracker table that will give me the table name to insert/read the data from, but I am not sure how I can use this with entity framework...
Thoughts?
You could try to use the Entity Inheritance to get this. So you have a base class which has all the fields mapped to ItemTable and then you have descendant classes that inherit from ItemTable entity and is mapped to the silo tables in the db. Every time you create a new silo you create a new entity mapped to that silo table.
[Table("ItemTable")]
public class Item
{
//All the fields in the table goes here
}
[Table("silo1_ItemTable")]
public class Silo1Item : Item
{
}
[Table("silo2_ItemTable")]
public class Silo2Item : Item
{
}
You can find more information on this here
Other option is to create a view that creates a union of all those table and map your entity to that view.
As mentioned in my comment, to solve this problem I am using the SQLQuery method that is exposed by DBSet. Since all my item tables have the exact same schema, I can use the SQLQuery to define my own query and I can pass in the name of the table to the query. Tested on my system and it is working well.
See this link for an explanation of running raw queries with entity framework:
EF raw query documentation
If anyone has a better way to solve my question, please leave a comment.
[UPDATE]
I agree that stored procedures are also a great option, but for some reason my management is very resistant to make any changes to our database. It is easier for me (and our customers) to put the sql in code and acknowledge the fact that there is raw sql. At least I can hide it from the other layers rather easily.
[/UPDATE]
Possible solution for this problem may be using context initialization with DbCompiledModel param:
var builder = new DbModelBuilder(DbModelBuilderVersion.V6_0);
builder.Configurations.Add(new EntityTypeConfiguration<EntityName>());
builder.Entity<EntityName>().ToTable("TableNameDefinedInRuntime");
var dynamicContext = new MyDbContext(builder.Build(context.Database.Connection).Compile());
For some reason in EF6 it fails on second table request, but mapping inside context looks correct on the moment of execution.

Change Table and Column Name Mappings Entity Framework v4.3

I've got an application with a working Entity model generated from an existing database. I have to point my application at a new database, with the same schema, except that the table and column names are different.
For example, my current schema has tables named like "Answer". My new schema that I need to point to has the exact same table, except it is named "tblAnswer".
My columns have also changed. Where as a column used to be called "AnswerId", it's now "zAnswerId". Don't ask about the "z" prefix, it's a long story, but it's on every column.
So, what options do I have to point this existing Entity Model (generated from the database) to a new database and adjust the mappings? I've been experimenting with some of the techniques that are used for "Code First" mappings, as outlined in this guide, but haven't had any luck. I simply don't know if this is the right approach, or if there is something that makes more sense.
Suggestions? Thanks in advance.
You can change the database in the web.config file.
Use data annotations to use the different table and column names.
For example:
[Table("tblAnswer")]
class Answer
{
[Column("zAnswerId")]
public int AnswerId { get; set; }
}

Adding a property to an Entity Framework Entity from another table

I'm just starting out with the Entity Framework and ADO.NET Data Services and I've run into an issue that I can't seem to figure out. I have two tables, one that has user information and the other that has a created by field. Within the database, there isn't a foreign key between these tables. The user table contains an arbitrary Id, a username, and a display name. The created by field contains the user's username. In my entity I would like to have the user's display name since this is what I need to display and expose over the ADO.NET Data Service? I'm aware that I could restructure the database, but I was hoping that I could do the join using the username as I would in a SQL statement.
Thanks in advance,
-Damien
You can make a view using a join of both tables, and then use this object to display the user's name.
There's some info on mapping custom queries here.