How to represent table with nulls in Spring Data JPA? - java

What should I do to represent this table in Spring Data Java Persistence Application Programming Interface (JPA)?
The table is specific because it has no primary key and every column in the table can have nulls, and it is read only.
In entity class I can not simply annotate a single column with #id because there is no column with unique values.
I can, of course, create composite virtual primary key in entity class by annotating every column with #id, and that works, but only if there are no nulls in the row. So if I select row(s) with all columns not null then this works. But if one or more columns contains null, Spring is not able to extract that row from table, and instead returns simply null for entire row rather than returning an entity object with only the appropriate field null.
Please do not say "just add id column to the table" because table is read only for us. My company was negotiating for more then a month just to get the read rights to the table! I can not simply add id field in the table.
What else can I do in this case? Other than manually executing a query and extracting the result. Can I somehow fake the id field to make Spring happy? id field is not important for our application, we will never filter the table by id, so it can be whatever makes Spring happy as far as I am concerned.

I don't think there is a way to do that.
Just get a NamedParameterJdbcTemplate injected and query away.
A central premise of JPA is that you can load data from a bunch of tables, edit the resulting object structure and JPA will take note and mirror the changes to the data in the database.
If you don't have anything to use as an id you wouldn't know which row to update. So this whole approach kinda fails to work.

You can use #EmeddedId with an ID you create. Set the ID field either #Transient or static so it won't affect persistence.
In the below example I use the UUID static method .randomUUID() to generate the ID.
So put this into your #Entity and you will get every row regardless of nulls. Inserts will work just fine too (depending on how you disambiguate your rows).
#EmbeddedId
static UUID uuid = UUID.randomUUID();

Related

Java, Hibernate, How to set Envers, so it won't create new versions if only one one field changed?

As in the title. I have an entity with lot of fields, but every time this entity is saved to data base, envers creates another version event if the only thing that changed is "modificationTimestamp". Is there any way to ignore that one field? But it also need to be written into db if any other field changes.
The easiest way would be to added the #NotAudited annotation to that property in your model. This means that field will no longer be used in the delta comparison to determine if the entity was modified and thus will no longer trigger an audit row to be added.
This also means you'll have a small inconsistency in your audit data because entries added prior will contain a value in this modificationTimestamp column where-as rows after adding the annotation will begin to contain null values because Envers no longer tracks this column.
If you don't need the values in the older rows, you can safely drop the column manually from the audit schema if its a value that is of no importance from an audit history perspective.
If you need the older values but the audit schema column was created with a not-null constraint in someway, you may need to alter the schema manually and allow it to insert null values simply due to the change in the behavior.

Hibernate and Spring Use in Analytics Tools

I want t integrate Hibernate and Spring Frame work in my product. But the thing that stopping me to use. Basically we have dynamic table and column name which change everyday. Currently getting data from table and displaying on UI is all decided at run time. which table to hit. same with the column names.
So how to implemented entity and other concept of hibernate and spring so the object will mapped to data?
for example this is the SQL
select t3521_250_1_1.f_1_1_31,sum(t3521_250_1_1.f_1_1_45) from t3521_250_1_1
where t3521_250_1_1.f_1_1_31 is not null
and t3521_250_1_1.f_1_1_45 is not null
group by t3521_250_1_1.f_1_1_31
order by sum(t3521_250_1_1.f_1_1_45) desc limit 5000000
in above Sql
Table Name = t3521_250_1_1
Column name = f_1_1_31,f_1_1_45
Now these table names and columns name are dynamic. Every day a new table is created with different name and this table has 64 columns but now I am hitting only two columns.
I hope you guyz understand what i want to say
I am not sure whether this is a fix. But can you try creating a view with constant field names and point the POJO to this view.
When you create the dynamic table you can update this view as well.

JPA map view with no primary key to an entity

I've got a database view with no primary key. It has a set of columns which uniquely identify a row in the view, but three of those columns can be null. I've tried creating an entity with a composite primary key based on those four columns but when retrieving data from the view I get this error:
The primary key read from the row ... during the execution of the query was detected to be null. Primary keys must not contain null.
Is there something I can do, for example, adding an automatically generated column when defining the view?
JPA Specification says that an Entity class must have a unique, immutable ID.
Logically, if it does not have any primary key, it can't be called entity. What you can do instead is create a POJO representation of your VIEW, then execute a SQL Native query, then map the result set to your POJO.
Here's a sample using #SqlResultSetMapping/#ConstructorResult
http://www.thoughts-on-java.org/result-set-mapping-constructor-result-mappings/
Not all entities have PKs that fit the definition of JPA. There are a couple of ways around it, all of them hacky.
1) modify the view to combine the fields (substituting nulls with sensible values) into one field, and map that as a PK
2) use the attribute converter functionality to substitute nulls with sensible values, then you can map the composite PK.
3) use RowID as a PK (this is ok only if you don't depend on the PK for anything long term, as RowIDs are not guranteed to stay consistent between runs.
I'm sure there are other similar workarounds, but I've used 1 and 2, and explored using 3.

How to get column from other tables, to form a new table?

I'm relatively new to working with JDBC and SQL. I have two tables, CustomerDetails and Cakes. I want to create a third table, called Transactions, which uses the 'Names' column from CustomerDetails, 'Description' column from Cakes, as well as two new columns of 'Cost' and 'Price'. I'm aware this is achievable through the use of relational databases, but I'm not exactly sure about how to go about it. One website I saw said this can be done using ResultSet, and another said using the metadata of the column. However, I have no idea how to go about either.
What you're probably looking to do is to create a 'SQL View' (to simplify - a virtual table), see this documentation
CREATE VIEW view_transactions AS
SELECT Name from customerdetails, Description from cakes... etc.
FROM customerdetails;
Or something along those lines
That way you can then query the View view_transactions for example as if it was a proper table.
Also why have you tagged this as mysql when you are using sqlite.
You should create the new table manually, i.e. outside of your program. Use the commandline 'client' sqlite3 for example.
If you need to, you can use the command .schema CustomerDetails in that tool to show the DDL ("metadata" if you want) of the table.
Then you can write your new CREATE TABLE Transactions (...) defining your new columns, plus those from the old tables as they're shown by the .schema command before.
Note that the .schema is only used here to show you the exact column definitions of the existing tables, so you can create matching columns in your new table. If you already know the present column definitions, because you created those tables yourself, you can of course skip that step.
Also note that SELECT Name from CUSTOMERDETAILS will always return the data from that table, but never the structure, i.e. the column definition. That data is useless when trying to derive a column definition from it.
If you really want/have to access the DB's metadata programatically, the documented way is to do so by querying the sqlite_master system table. See also SQLite Schema Information Metadata for example.
You should read up on the concept of data modelling and how relational databases can help you with it, then your transaction table might look just like this:
CREATE TABLE transactions (
id int not null primary key
, customer_id int not null references customerdetails( id )
, cake_id int not null references cakes( id )
, price numeric( 8, 2 ) not null
, quantity int not null
);
This way, you can ensure, that for each transaction (which is in this case would be just a single position of an invoice), the cake and customer exist.
And I agree with #hanno-binder, that it's not the best idea to create all this in plain JDBC.

JPA: InvalidStateException Error + Composite Key/EmbeddableId/Sequence Generated IDs

I currently have a schema set up with my database and Java Application using OpenJPA that works most of the time, but sometimes I get the error for a few users:
org.apache.openjpa.persistence.InvalidStateException: Attempt to set column "table1.ID" to two different values
table1 actually has a composite Key (two values) and each value in that key is a foreign key to another table. I used RSA (Rational Software Architect) to set up the entities for me (generated code). It set up a PK class (using #EmbeddableId to reference the PK class) in the Entity class for table1, and then two #ManyToOne relationships in the same table1 Entity class (and also in the entity classes that those columns reference) since they are foreign keys
Now, as I mentioned above, each value in the composite key is a foreign key. Well, each of those foreign keys is actually generated using an outside Sequencer in their own entity classes. I am using DB2 and using #GeneratedValue on the columns (i.e. the IDs in table2's and table3's entity classes). I use strategy=GenerationType.SEQUENCE also for each.
Again, everything works USUALLY but not 100% of the time and I'm unsure why. I have gotten rid of this error by wiping out everything and resetting the Sequence Generators, but I know this is definitely not a solution. Could it have something to do with the fact that the two Composite Key values in the database are foreign keys to columns which were generated using a sequence, but the PK entity might not know?
I have noticed too that it only works for users who have a record in the Users table (one of the foreign keys mentioned above is to a Users table, while the other FK is to another table). What happens, if a user is not in the table, it creates one, something like:
User newUser = userManager.getNewUser();
newUser.setName(..);
newUser.setEmail(..);
...
When it's done, the PK class I mentioned above has a new instance of that created, which is then called into another table. The ID from the user above is passed into the PK. Like:
PK newPK = pkManager.getNewPK();
newPk.setAID(newUser.getID());
Has anybody run into this? Any solutions?
Sorry, fixed the problem. I went through my code and realized I had forgot to refactor one line of code (change in data model).

Categories

Resources