Persist product in broadleaf database - java

I am fetching products and categories from other source. I want to persist them in broadleaf database. I don't want auto generated ids. I want to persist id comes from source(from where I am fetching products etc.) to broadleaf database.
For that I have created my custom controller : http://www.broadleafcommerce.com/docs/core/current/broadleaf-concepts/admin/admin-custom-controllers
I am writing product and category persisting code in MyController.
I have tried following code :
Category category = catalogService.createCategory();
Long categoryId = new Long(453510);
category.setId(categoryId);
category.setName("test category4");
category.setUrl("/test-category4");
catalogService.saveCategory(category);
Product p = catalogService.createProduct(ProductType.PRODUCT);
Sku newSku = catalogService.createSku();
Long skuId = new Long(453520);
newSku.setId(skuId);
p.setDefaultSku(newSku);
p.getDefaultSku().setDefaultProduct(p);
p.setName("test product4");
p.setUrl("/test-product4");
p.setCategory(category);
Long productId = new Long(453530);
p.setId(productId);
catalogService.saveProduct(p);
I am getting following stacktrace :
Caused by: org.postgresql.util.PSQLException: ERROR: insert or update on table "blc_sku" violates foreign key constraint "fk28e82cf77e555d75"
Detail: Key (default_product_id)=(453530) is not present in table "blc_product".
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2182)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1911)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:173)
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:645)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:495)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:441)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
If I remove below snippet, then it gives me null pointer because product object required to set default sku.
Sku newSku = catalogService.createSku();
Long skuId = new Long(453520);
newSku.setId(skuId);
p.setDefaultSku(newSku);
p.getDefaultSku().setDefaultProduct(p);
Please help me to persist product with given id( not autogenerated) in broadleaf database.

Because Hibernate is configured to generate the values for the id attributes on these entities, Hibernate is forcing the next generated value even though you have attempted to override the value. It appears that your override value is being used for the foreign key and Hibernate's generated value is being set for the primary key resulting in the FK constraint violation.
These entities (category, product, sku) have been designed with the assumption that users would be importing from external systems and because of that, they each have an externalId attribute defined. The recommended approach is to let Hibernate manage the pk/fk values via the generator and then the externalId attributes are used for mapping external systems into these entities.
If your requirement does not allow the use of the externalId, you could look at trying to override the generator annotation on those attributes using load time weaving. There is no Broadleaf mechanism to override an existing annotation on an attribute so this would be a customization you would have to explore.

Related

JPA mapping with two ManyToOne using an intermediary table (middle entity)

I am trying to set a JPA mapping with JoinTable, and it seems to be ignored when Hibernate (my JPA implementation) is doing a query.
To explain the use case
Each time a user gets a page of my app, I insert a line in the USAGE_LOG table (with the id of the user and the id of the page).
Each page is related to a category (for instance: settings, orders, items, news...) and a type (for instance create, update, display, delete).
So, I have some kind of middle entity table, that links a page to: a category + a type. Like a triplet: (page, category, type)
My table structure
table USAGE_LOG (for information only, this one works well)
ID PrimaryKey
USER_ID Foreign key to column ID of table USER
USAGE_LOG_PAGE_ID Foreign key to column ID of table USER_LOG_PAGE
table USAGE_LOG_PAGE
ID PrimaryKey
URL VARCHAR
USER_ACTION_ID Foreign key to column ID of table USER_ACTION
table USER_ACTION
ID PrimaryKey
ACTION_CATEGORY_ID Foreign key to column ID of table ACTION_CATEGORY
ACTION_TYPE_ID Foreign key to column ID of table ACTION_CATEGORY
table ACTION_CATEGORY
ID PrimaryKey
NAME VARCHAR
table ACTION_TYPE
ID PrimaryKey
NAME VARCHAR
So the USER_ACTION table is a join table with the particularity that it links a USAGE_LOG_PAGE to a ACTION_CATEGORY and a ACTION_TYPE at the same time.
Also, I can have several USAGE_LOG_PAGE that are linked to the same ACTION_CATEGORY and ACTION_TYPE.
Unfortunately, I cannot change the database structure (it is legacy code).
I have tried the following Mappping on the Entity "UsageLogPage"
#ManyToOne
#JoinTable(name="action",
joinColumns=#JoinColumn(name="ID", referencedColumnName="USER_ACTION_ID"),
inverseJoinColumns=#JoinColumn(name="ACTION_CATEGORY_ID", referencedColumnName="ID"))
#Getter #Setter
private ActionCategory actionCategory;
#ManyToOne
#JoinTable(name="action",
joinColumns=#JoinColumn(name="ID", referencedColumnName="USER_ACTION_ID"),
inverseJoinColumns=#JoinColumn(name="ACTION_TYPE_ID", referencedColumnName="ID"))
#Getter #Setter
private ActionType actionType;
(I use Lombok for #Getter and #Setter)
This mapping compiles, but when I try to get data, I have the following exception:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'usagelogpa0_.actionCategory' in 'field list'
Indeed, the Hibernate query is:
select usagelogpa0_.ID as ID1_80_0_,
usagelogpa0_.actionCategory as actionCa2_80_0_,
usagelogpa0_.actionType as actionTy3_80_0_,
usagelogpa0_.URL as URL5_80_0_
from usage_log_page usagelogpa0_
where usagelogpa0_.ID=?
(the key part is the "actionCategory" and "actionType" in the select)
This is not what I expect, Hibernate should do a join.
Have you any idea of what I did wrong?
Thanks !
After lots of investigations, I have found that:
it wasn't working as expected because I put the #ManyToOne and the #JoinTable annotations at the attribute level. I created a getter by hand and put the annotations on it, and they were taken into account
it still wasn't working correctly, because Hibernate didn't find the column "USER_ACTION_ID" on the USAGE_LOG_PAGE table, at run time. This column wasn't in the available fields, for a reason (that I coudn't find). When adding a field "usage_action_id" in the entity "UsageLogPage", it found the attribute, but refused to create the mapping because USAGE_ACTION_ID isn't a primary key.
At the end, even if I couldn't change the database, I could change the object model.
So I created the middle entity "UserAction", binded it with ManyToOne on the UsageLogPage entity, removed the attribute "actionCategory" and "actionType" from the UsageLogPage and added them as ManyToOne in the new UserAction entity.
If you have a table that acts as a middle entity for 2 different ManyToOne relationships, perhaps the best solution is to create the middle entity in your object model.

redundant id values inserted despite using #inheritance

In a spring mvc app using hibernate, jpa, and MySQL, I have a BaseEntity that contains an id field that is unique across all classes that inherit from BaseEntity, using #Inheritance(strategy = InheritanceType.TABLE_PER_CLASS). Some data is imported into the MySQL database using an external dml.sql file run from the command line. The imported data is carefully planned so that all the ids that need to be managed as part of the BaseEntity inheritance group are unique within their inheritance group.
The problem is that hibernate is not taking the values of the ids already in the database into account when it inserts a new record into the database. Instead, hibernate is saving an id value in one of the descendent entities which is identical to an id stored in one of the other descendent entities.
How can I configure hibernate to respect the id values already in the database when it saves a new entity within the same inheritance group?
Some relevant facts are:
All of the objects in the MySQL database were created directly from the hibernate mappings in the app by using hbm2ddl.
I cannot use #MappedSuperClass for BaseEntity because BaseEntity is used as a property of one of the entities in the app, so that entities of various types can be stored in the same property of that entity. When I was using #MappedSuperClass, eclipse was giving compile errors saying that BaseEntity cannot be instantiated directly because it has #MappedSuperClass annotation.
Note: The file sharing site seems to be center-justifying all the code. You can fix this by simply cutting and pasting it into a text editor.
You can read the code for BaseEntity by clicking on this link.
The code for the entity whose id values are being set incorrectly by hibernate can be read by clicking on this link.
The jpql code for saving the entity whose id is being set incorrectly is as follows:
#Override
#Transactional
public void saveCCD(HL7ConsolidatedCareDocument ccd) {
if (ccd.getId() == null) {
this.em.persist(ccd);
this.em.flush();
}
else {
this.em.merge(ccd);
this.em.flush();
}
}
I have never done this using hibernate or mysql ut have done something similar with EclipseLink + PostgreSQL. So there might be some mistakes below.
With generation type TABLE you might want to explicitly specify some additional parameters using the TableGenerator annotation. That way you are certain where hibernate is storing things.
#Id
#GeneratedValue(
strategy=GenerationType.TABLE,
generator="TBL_GEN")
#javax.persistence.TableGenerator(
name="TBL_GEN",
table="GENERATOR_TABLE",
pkColumnName = "mykey",
valueColumnName = "hi"
pkColumnValue="BaseEntity_Id",
allocationSize=20
)
What you need to do when you bypass hibernate is to reserve the ids you need by updating the row with mykey BaseEntity_Id in the table GENERATOR_TABLE.
For details on the annotations see paragraph 5.1.2.2

Manually update the counter used for generation of primary key in Hibernate?

In my spring project, the tables in database are created automatically by Hibernate using my entity classes as base, but I insert some default values in the table manually (using pgAdmin3).
Because that, I am facing now this problem: when I try insert a value via Java code in one of the tables which already have values, I receive a error message, saying the primary key already exists in the database.
Anyone knows how to solve this problem?
UPDATE
That's how I declare my primary key in my class:
#Id
#Column(name = "id")
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
Call this SQL query once per table to set the sequence to the next free number:
SELECT setval('tblname_id_seq', max(id)) FROM tblname;
tblname being the actual name of the table.
Hibernate may use a different naming convention, or the sequence may have been renamed. If you can't find the sequence behind the serial column, check with (per documentation):
SELECT pg_get_serial_sequence(tblname, column_name)
More details:
Modify Django AutoField start value
How to import a CSV to postgresql that already has ID's assigned?
The problem here might be that you declare the id as a primitive instead of a wrapper.
So instead of:
private int id;
You should have:
private Integer id;
When you create the entity with the id is initialized as 0, instead of NULL.
That's why you get duplicate id constraint violation exceptions.
Only when the id is NULL the AUTO generation strategy will delegate the id assignment to the database.

Hibernate null constraint violation on #Id with #GeneratedValue

I am using Hibernate 4.1.3 (JPA) on the Play! framework. The database is PostgreSQL 8.4.2. The schema was generated using hibernate.hbm2ddl.auto="update".
Short version: I have a class that has an #Id field that is a #GeneratedValue. Sometimes, when persisting it, I get a null-column violation, why?
More details:
I have a really simple class that I want to save to the database, that looks like this:
#Entity
class MyObject {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Long id;
#NotNull
public String email;
public Integer total;
}
I usually create an instance of MyObject, I assign a value to email and total fields while id is null and I save it via EntityManager.persist(). Hibernate gets an id for the new object and saves it to the DB.
However sometimes, I get the following stacktrace:
2012-05-19 00:45:16,335 - [ERROR] - from org.hibernate.engine.jdbc.spi.SqlExceptionHelper [SqlExceptionHelper.java:144] in play-akka.actor.actions-dispatcher-6
ERROR: null value in column "id" violates not-null constraint
2012-05-19 00:45:16,350 - [ERROR] - from application in play-akka.actor.actions-dispatcher-6
! #6ad7j3p8p - Internal server error, for request [POST /method] ->
play.core.ActionInvoker$$anonfun$receive$1$$anon$1: Execution exception [[PersistenceException: org.hibernate.exception.ConstraintViolationException: ERROR: null value in column "id" violates not-null constraint]]
How is this possible? How can I track down the problem?
Here's the relevant DDL generated by Hibernate:
CREATE TABLE myobject (
id bigint NOT NULL,
email character varying(255) NOT NULL,
physical integer
);
CREATE SEQUENCE hibernate_sequence
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;
ALTER TABLE ONLY dailydetailedscore
ADD CONSTRAINT dailydetailedscore_pkey PRIMARY KEY (id);
Try the annotation #org.hibernate.annotations.GenericGenerator(name = “test-hilo-strategy”, strategy = “hilo”):
#Id
#org.hibernate.annotations.GenericGenerator(name=“hilo-strategy”, strategy = “hilo”)
#GeneratedValue(generator = ”hilo-strategy”)
As someone noted above, AUTO does not do what you think. It uses the underlying DB to determine how to generate values. It may pick sequences (for oracle), identity column (for mssql), or something else that is db specific.
The approach here uses an internal strategy that Hibernate supplies called "hilo".
See chapter 5 of the Hibernate reference manual dealing with "Generator" for a full description of what each of the supplied ones does.
Neither the OP solution nor Matt's solution worked with my PostgreSQL 9.3.
But this one works:
#SequenceGenerator(name="identifier", sequenceName="mytable_id_seq", allocationSize=1)
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="identifier")
Replace mytable_id_seq with the name of the sequence that generates your id.
Use Hibernate method:- save(String entityName, Object object)
Persist the given transient instance, first assigning a generated identifier.
Do not use :- #GeneratedValue(strategy=GenerationType.IDENTITY) for primary key if you want to persist user define Id.
For detail:-
http://docs.jboss.org/hibernate/core/3.6/javadocs/org/hibernate/Session.html#save(java.lang.String
In mycase i was using Identity generation strategy and i have set the wrong data type in Postgres. Following steps i performed to debug the problem.
set
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true in application.properties and Drop the tables.
By this hibernate will automatically create the schema for you on the basis of your data-type.I noticed change in the datatype of id field.
Now when i tried any post requests, everything worked fine.

How to bind uuid field with spring mvc and hibernate

I have entity class which is annotated with hibernate and MySQL. I want to generate a UUID and insert it in the user table.
How can I map that field with hibernate?
How to bind that field with spring mvc and jsp because that
field will be autogenerated and won't be in the user form?
It's been a while since I wrote any Hibernate but I'm fairly sure you can just initialise it on construction and the id will be written to the DB on save and loaded from the db on load. You may find that a random UUID is less performant than the standard long primary key.
class MyEntity {
#Id
private String id = UUID.randomUUID().toString();
Well, you shouldn't bind any fields in your Form object that the user isn't actually filling out in the HTML form. Just let the DAO and backend classes deal with populating any sort of auto-generated ID.
As for generating a UUID with Hibernate, you can use Hibernate's built-in uuid generator or one of several other built-in generators, or you can use whatever type of unique ID generation logic is built into your Database Engine and just mark the ID field with <generator class="select"/> to have Hibernate query the database after inserting the row to find out the database-generated ID.

Categories

Resources