How do I reference Postgres constraints in j00q? - java

Using jooq 3.11.8, referencing a constraint in an onConflictOnConstraint is not particularly discoverable, and the documentation is exactly no help. I know the name of the constraint, but onConflictOnConstraint doesn't take a String.
Specifically:
ctx.insertInto(
TABLE,
TABLE.ID,
TABLE.FIELD1
)
.values(
id,
value
)
.onConflictOnConstraint(/* WHAT GOES HERE? */)
.doUpdate()
.set(TABLE.FIELD1, value)
.execute();
What am I missing?

There are 3 overloads of this method:
onConflictOnConstraint(Constraint): Use this with constraints defined through DSL.constraint(), i.e. the DDL API
onConflictOnConstraint(Name): Use this with DSL.name(), a way to create ad hoc identifier references
onConflictOnConstraint(UniqueKey): Use this with generated UniqueKey references in generated tables, e.g. as obtained from Table.getPrimaryKey()

Related

org.springframework.orm.jpa.JpaSystemException: identifier of an instance of com.cc.domain.User was altered from 90 to null; [duplicate]

org.hibernate.HibernateException: identifier of an instance
of org.cometd.hibernate.User altered from 12 to 3
in fact, my user table is really must dynamically change its value, my Java app is multithreaded.
Any ideas how to fix it?
Are you changing the primary key value of a User object somewhere? You shouldn't do that. Check that your mapping for the primary key is correct.
What does your mapping XML file or mapping annotations look like?
You must detach your entity from session before modifying its ID fields
In my case, the PK Field in hbm.xml was of type "integer" but in bean code it was long.
In my case getters and setter names were different from Variable name.
private Long stockId;
public Long getStockID() {
return stockId;
}
public void setStockID(Long stockID) {
this.stockId = stockID;
}
where it should be
public Long getStockId() {
return stockId;
}
public void setStockId(Long stockID) {
this.stockId = stockID;
}
In my case, I solved it changing the #Id field type from long to Long.
In my particular case, this was caused by a method in my service implementation that needed the spring #Transactional(readOnly = true) annotation. Once I added that, the issue was resolved. Unusual though, it was just a select statement.
Make sure you aren't trying to use the same User object more than once while changing the ID. In other words, if you were doing something in a batch type operation:
User user = new User(); // Using the same one over and over, won't work
List<Customer> customers = fetchCustomersFromSomeService();
for(Customer customer : customers) {
// User user = new User(); <-- This would work, you get a new one each time
user.setId(customer.getId());
user.setName(customer.getName());
saveUserToDB(user);
}
In my case, a template had a typo so instead of checking for equivalency (==) it was using an assignment equals (=).
So I changed the template logic from:
if (user1.id = user2.id) ...
to
if (user1.id == user2.id) ...
and now everything is fine. So, check your views as well!
It is a problem in your update method. Just instance new User before you save changes and you will be fine. If you use mapping between DTO and Entity class, than do this before mapping.
I had this error also. I had User Object, trying to change his Location, Location was FK in User table. I solved this problem with
#Transactional
public void update(User input) throws Exception {
User userDB = userRepository.findById(input.getUserId()).orElse(null);
userDB.setLocation(new Location());
userMapper.updateEntityFromDto(input, userDB);
User user= userRepository.save(userDB);
}
Also ran into this error message, but the root cause was of a different flavor from those referenced in the other answers here.
Generic answer:
Make sure that once hibernate loads an entity, no code changes the primary key value in that object in any way. When hibernate flushes all changes back to the database, it throws this exception because the primary key changed. If you don't do it explicitly, look for places where this may happen unintentionally, perhaps on related entities that only have LAZY loading configured.
In my case, I am using a mapping framework (MapStruct) to update an entity. In the process, also other referenced entities were being updates as mapping frameworks tend to do that by default. I was later replacing the original entity with new one (in DB terms, changed the value of the foreign key to reference a different row in the related table), the primary key of the previously-referenced entity was already updated, and hibernate attempted to persist this update on flush.
I was facing this issue, too.
The target table is a relation table, wiring two IDs from different tables. I have a UNIQUE constraint on the value combination, replacing the PK.
When updating one of the values of a tuple, this error occured.
This is how the table looks like (MySQL):
CREATE TABLE my_relation_table (
mrt_left_id BIGINT NOT NULL,
mrt_right_id BIGINT NOT NULL,
UNIQUE KEY uix_my_relation_table (mrt_left_id, mrt_right_id),
FOREIGN KEY (mrt_left_id)
REFERENCES left_table(lef_id),
FOREIGN KEY (mrt_right_id)
REFERENCES right_table(rig_id)
);
The Entity class for the RelationWithUnique entity looks basically like this:
#Entity
#IdClass(RelationWithUnique.class)
#Table(name = "my_relation_table")
public class RelationWithUnique implements Serializable {
...
#Id
#ManyToOne
#JoinColumn(name = "mrt_left_id", referencedColumnName = "left_table.lef_id")
private LeftTableEntity leftId;
#Id
#ManyToOne
#JoinColumn(name = "mrt_right_id", referencedColumnName = "right_table.rig_id")
private RightTableEntity rightId;
...
I fixed it by
// usually, we need to detach the object as we are updating the PK
// (rightId being part of the UNIQUE constraint) => PK
// but this would produce a duplicate entry,
// therefore, we simply delete the old tuple and add the new one
final RelationWithUnique newRelation = new RelationWithUnique();
newRelation.setLeftId(oldRelation.getLeftId());
newRelation.setRightId(rightId); // here, the value is updated actually
entityManager.remove(oldRelation);
entityManager.persist(newRelation);
Thanks a lot for the hint of the PK, I just missed it.
Problem can be also in different types of object's PK ("User" in your case) and type you ask hibernate to get session.get(type, id);.
In my case error was identifier of an instance of <skipped> was altered from 16 to 32.
Object's PK type was Integer, hibernate was asked for Long type.
In my case it was because the property was long on object but int in the mapping xml, this exception should be clearer
If you are using Spring MVC or Spring Boot try to avoid:
#ModelAttribute("user") in one controoler, and in other controller
model.addAttribute("user", userRepository.findOne(someId);
This situation can produce such error.
This is an old question, but I'm going to add the fix for my particular issue (Spring Boot, JPA using Hibernate, SQL Server 2014) since it doesn't exactly match the other answers included here:
I had a foreign key, e.g. my_id = '12345', but the value in the referenced column was my_id = '12345 '. It had an extra space at the end which hibernate didn't like. I removed the space, fixed the part of my code that was allowing this extra space, and everything works fine.
Faced the same Issue.
I had an assosciation between 2 beans. In bean A I had defined the variable type as Integer and in bean B I had defined the same variable as Long.
I changed both of them to Integer. This solved my issue.
I solve this by instancing a new instance of depending Object. For an example
instanceA.setInstanceB(new InstanceB());
instanceA.setInstanceB(YOUR NEW VALUE);
In my case I had a primary key in the database that had an accent, but in other table its foreign key didn't have. For some reason, MySQL allowed this.
It looks like you have changed identifier of an instance
of org.cometd.hibernate.User object menaged by JPA entity context.
In this case create the new User entity object with appropriate id. And set it instead of the original User object.
Did you using multiple Transaction managers from the same service class.
Like, if your project has two or more transaction configurations.
If true,
then at first separate them.
I got the issue when i tried fetching an existing DB entity, modified few fields and executed
session.save(entity)
instead of
session.merge(entity)
Since it is existing in the DB, when we should merge() instead of save()
you may be modified primary key of fetched entity and then trying to save with a same transaction to create new record from existing.

JOOQ arrayAgg array_agg fields as object

I have 2 entities:
record Customer(String name, List<CustomerContact > contactHistory) {}
record CustomerContact(LocalDateTime contactAt, Contact.Type type) {
public enum Type {
TEXT_MESSAGE, EMAIL
}
}
These are persisted in a schema with 2 tables:
CREATE TABLE customer(
"id". BIGSERIAL PRIMARY KEY,
"name" TEXT NOT NULL
);
CREATE TABLE customer_contact(
"customer_id" BIGINT REFERENCES "customer" (ID) NOT NULL,
"type" TEXT NOT NULL,
"contact_at" TIMESTAMPTZ NOT NULL DEFAULT (now() AT TIME ZONE 'utc')
);
I want to retrieve the details of my Customers with a single query, and use the arrayAgg method to add the contactHistory to each customer. I have a query like this:
//pseudo code
DSL.select(field("customer.name"))
.select(arrayAgg(field("customer_contact.contact_at")) //TODO How to aggregate both fields into a CustomerContact object
.from(table("customer"))
.join(table("customer_contact")).on(field("customer_contact.customer_id").eq("customer.id"))
.groupBy(field("customer_contact.customer_id"))
.fetchOptional()
.map(asCustomer());
The problem I have with this is that arrayAgg will only work with a single field. I want to use 2 fields, and bind them into a single object (CustomerContact) then use that as the basis for the arrayAgg
Apologies if I have not explained this clearly! Any help much appreciated.
Rather than using ARRAY_AGG, how about using the much more powerful MULTISET_AGG or MULTISET to get the most out of jOOQ's type safe capabilities? Combine that with ad-hoc conversion for type safe mapping to your Java records, as shown also in this article. Your query would then look like this:
Using MULTISET_AGG
List<Customer> customers =
ctx.select(
CUSTOMER.NAME,
multisetAgg(CUSTOMER_CONTACT.CONTACT_AT, CUSTOMER_CONTACT.TYPE)
.convertFrom(r -> r.map(Records.mapping(CustomerContact::new))))
.from(CUSTOMER)
.join(CUSTOMER_CONTACT).on(CUSTOMER_CONTACT.CUSTOMER_ID.eq(CUSTOMER.ID))
.groupBy(CUSTOMER_CONTACT.CUSTOMER_ID)
.fetch(Records.mapping(Customer::new));
Note that the entire query type checks. If you change anything about the query or about your records, it won't compile anymore, giving you additional type safety. This is assuming that youre Type enum is either:
Generated from a PostgreSQL ENUM type
Converted automatically using an enum converter, attached to generated code
Depending on your tastes, using implicit joins could slightly simplify the query for you?
List<Customer> customers =
ctx.select(
CUSTOMER_CONTACT.customer().NAME,
multisetAgg(CUSTOMER_CONTACT.CONTACT_AT, CUSTOMER_CONTACT.TYPE)
.convertFrom(r -> r.map(Records.mapping(CustomerContact::new))))
.from(CUSTOMER_CONTACT)
.groupBy(CUSTOMER_CONTACT.CUSTOMER_ID)
.fetch(Records.mapping(Customer::new));
It's not a big deal in this query, but in a more complex query, it can reduce complexity.
Using MULTISET
An alterantive is to nest your query instead of aggregating, like this:
List<Customer> customers =
ctx.select(
CUSTOMER.NAME,
multiset(
select(CUSTOMER_CONTACT.CONTACT_AT, CUSTOMER_CONTACT.TYPE)
.from(CUSTOMER_CONTACT)
.where(CUSTOMER_CONTACT.CUSTOMER_ID.eq(CUSTOMER.ID))
).convertFrom(r -> r.map(Records.mapping(CustomerContact::new))))
.from(CUSTOMER)
.fetch(Records.mapping(Customer::new));
Code generation
For this answer, I was assuming you're using the code generator (you should!), as it would greatly contribute to this code being type safe, and make this answer more readable.
Much of the above can be done without code generation (except implicit joins), but I'm sure this answer could nicely demonstrate the benefits it terms of type safety.

How to use CacheConfiguration.setIndexedTypes for Ignite Cache

I am following the code for the running SQL queries in the Ignite cache, but am able to fully realize the use of the CacheConfiguration.setIndexedTypes API.
I am following the only help that I could find at the ignite site.
The documentation here says to use
CacheConfiguration.setIndexedTypes(MyKey.class, MyValue.class).
Now lets say in the Person class
#QuerySqlField(index = true)
private long id;
#QuerySqlField
private String firstName;
Which are the parameters that I should be passing in the setIndexedType method?
setIndexedTypes takes an even number of parameters. Every odd parameter corresponds to a key type, and every even - to a value type. In your case you should probably use id parameter as a key, so you should call it this way:
cacheConfig.setIndexedTypes(Long.class, Person.class);
Javadoc for setIndexedTypes method contains a pretty good explanation of this method: https://ignite.apache.org/releases/latest/javadoc/org/apache/ignite/configuration/CacheConfiguration.html#setIndexedTypes(java.lang.Class...)
UPD:
There will be registered a table in SQL for each pair of parameters that you provide to setIndexedTypes method.
Your SQL entities will map to cache records and they will have _key and _val columns in addition to the ones that you configured as QuerySqlField-s. So, you should specify types of keys and values that will be used in cache for each table.
You can refer to this page for more information: https://apacheignite.readme.io/docs/dml#basic-configuration
In your case it will be
cacheConfig.setIndexedTypes(KeyType.class, Person.class)
where KeyType is the type you use for keys while calling cache.put(key, person) or insert into Person(_key, ...) ...
Please refer to this documentation section

DynamoDBMappingException: no mapping for HASH key

When writing a DynamoDB Java App you can receive the 'no mapping for HASH key' error when writing or retrieving from a table if the table and its data model are not configured correctly. The full exception would be similar to:
com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMappingException: <YourClassNameHere>; no mapping for HASH key
Make sure that your annotated mapped class's getters are declared public.
Two helpful things to check here:
1) For your main setter for your hash key value make sure that the #DynamoDBHashKey notation is correctly set. #DynamoDBAttribute is NOT the correct one to use for your table's main hash key and neither is #DynamoDBIndexHashKey.
2) Make sure that the hash key is defined in the table definition:
CreateTableRequest createTableRequest = new CreateTableRequest()
.withTableName("testtable")
.withKeySchema(
new KeySchemaElement("id", KeyType.HASH)
)
.withProvisionedThroughput(new ProvisionedThroughput(1L, 1L))
.withAttributeDefinitions(
new AttributeDefinition("id", "S")
);
CreateTableResult result = amazonDynamoDB.createTable(createTableRequest);
The above table definition creates a table 'testtable' with a main index or hash key variable titled id and the type is S for string.
Additionally, if you are using inheritance, make sure that you don't have two functions with the same name that override each other. Dynamo will use the top-level getter and this can cause issues.
If you are using #Data annotation (lombok.data), Try again after removing it and generate getters and setters for all the Attributes(including the primary_key/partition_key).

Query enum in hibernate throws DataException: Bad value for type int : t

I have a table with an Enum type attribute mapped like this:
#Enumerated(EnumType.ORDINAL)
#Column(name = "status")
private Enums.Status status;
Where the Enums.Status is
public enum Status {
CHECKED(1),
DISABLED(2),
INACTIVE(3);
int id;
// constructor + getter
}
And the column status from the database is stored as type int4
I am querying the table with the following HQL:
Query q = session.createQuery(" from Users where status=:account");
query.setParameter("account", Enums.Status.CHECKED);
List<Users> users = query.list();
The above code works fine on my testing server, but when on the production server it throws the following exception:
org.hibernate.exception.DataException: Bad value for type int : t
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:134)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:125)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:110)
at org.hibernate.engine.jdbc.internal.proxy.AbstractResultSetProxyHandler.continueInvocation(AbstractResultSetProxyHandler.java:108)
at org.hibernate.engine.jdbc.internal.proxy.AbstractProxyHandler.invoke(AbstractProxyHandler.java:81)
at com.sun.proxy.$Proxy30.getInt(Unknown Source)
at org.hibernate.type.EnumType$OrdinalEnumValueMapper.getValue(EnumType.java:358)
at org.hibernate.type.EnumType.nullSafeGet(EnumType.java:105)
at org.hibernate.type.CustomType.nullSafeGet(CustomType.java:127)
at org.hibernate.type.AbstractType.hydrate(AbstractType.java:106)
at org.hibernate.persister.entity.AbstractEntityPersister.hydrate(AbstractEntityPersister.java:2873)
at org.hibernate.loader.Loader.loadFromResultSet(Loader.java:1668)
at org.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:1600)
at org.hibernate.loader.Loader.getRow(Loader.java:1500)
at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:712)
at org.hibernate.loader.Loader.processResultSet(Loader.java:940)
at org.hibernate.loader.Loader.doQuery(Loader.java:910)
I tried replacing the enum parameter with its .ordinal() value, but received another exception. I tried looking up the differences between the testing server and the production server, but they both use the same java version, hibernate library, datatypes for the table and table content.
Has anyone ever encountered any similar issue or has any idea how it could be fixed?
I have figured out the problem. In our case the production server has multiple schemas and a database update failed on one of them, resulting in a field having a different data type then its hibernate mapping.
In case anyone gets here looking for an answer to the same error, try the following:
For enums, verify that the datatype in the db is integer for mapping #Enumerated(EnumType.ORDINAL) (or varchar for EnumType.STRING)
Verify that all other data types of that table match the hibernate mapping
Verify that the values inside the db do not exceed the number of items in the enum
Verify data in all schemas (if you are using multiple)
If you are experiencing this error on one server and not on another, check for the following differences: jdk version, hibernate-core version, database driver version. If they are all the same, try dumping the database from one server to another
With Java Enums, the term ordinal does not refer to an id property, but to a built in property of the Enum class. See JavaDocs for the ordinal() method.
Returns the ordinal of this enumeration constant (its position in its enum declaration, where the initial constant is assigned an ordinal of zero). Most programmers will have no use for this method. It is designed for use by sophisticated enum-based data structures, such as EnumSet and EnumMap.
Note that the first ordinal is 0 (zero) not 1
Don't be calling the ordinal() method yourself; let Hibernate do that.

Categories