Map Cassandra Materialized View with DSE's Java API - java

I have a cassandra table with an associated materialized view.
The primary key is a single id of type uuid, and I have no sort key. Let's call it my_table_id. This table contains a related_id that I want to use to search.
Then I have a materialized view for that table defined as
PRIMARY KEY (related_id, my_table_id) WITH CLUSTERING ORDER BY (my_table_id ASC)
PS: I realise it's the wrong way to partition data in Cassandra, but unfortunately, this code was inherited.
I'm defining my table in my java code as:
#Table(table = "my_table")
public class MyTableType {
#PartitionKey
#Column("my_table_id")
#Codec(MyIdCassandraConverter.class)
CustomUUIDType myTableId;
#Column("related_id")
#Codec(MyRelatedIdCassandraConverter.class)
MyRelatedId relatedId;
(...)
}
Those two custom types are simply wrappers around UUIDs. Again, inherited.
My materialized view is defined as:
#MaterializedView(baseEntity = MyTableType.class, view = "my_table_by_related_id")
public class MyTableTypeByRelatedId {
#PartitionKey
#Column("related_id")
#Codec(MyRelatedIdCassandraConverter.class)
MyRelatedId relatedId;
#ClusteringColumn
#Column("my_table_id")
#Codec(MyIdCassandraConverter.class)
CustomUUIDType myTableId;
}
The code seems to be generated correctly, but when I start my Spring Boot application, I get:
Error:java: Cannot find base entity class
'mypackage.MyTableType' for view class
'mypackage.MyTableTypeByRelatedId'
Error:java: Error while parsing: Cannot find base entity class
'mypackage.MyTableType' for view class
'mypackage.MyTableTypeByRelatedId'
There's some code generation going on, so it seems to be something's not generated correctly, but I can't quite figure out what.
The only mildly useful documentation I find is here and here, but none seems to offer help.
What am I doing wrong?

Well, not much of an answer, because this was not much of a question, but someone having a similar problem might find it useful.
This specific problem was caused because I was looking at the wrong database, which of course didn't have the tables and views I created. I had a property override file I thought was set correctly, and that was my mistake.

have you tried to add keyspace value on your #MaterializedView annotation?
#MaterializedView(keyspace = "xxxx", baseEntity = MyTableType.class, view = "my_table_by_related_id")

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.

Spring Boot cannot successfully POST data to db (ORA-00942)

I'm new to Spring Boot. I've stucked in the problem of creating new data (POST) for a whole day.
The error shows that I did not connect successfully to the db (ORA-00942).
Due to some privacy issues, I cannot copy-paste my work through my device. Therefore, I'm going to try my best to describe my logic and type out part of my codes. Any ideas would be a huge help! Thanks a million!
I have five packages here, which are basically classified by
(1.)SpringBootApplication package, (2.)Repository package(3.)Service package (4.)Controller
package (5.)Entity package
Basically, I do not edit in (1.)SpringBootApplication package, it's
kept originally as default.
In my (5.)Entity package, I have written an Entity class that matches
my db. Let's say the class name of this Entity is called TitleOfMyDb. Here, Ive written the correspond #id properly, and I also write the setters and getters correctly.
In the (3.)Service package, there is an Interface and a class. The class
is basically the implementation of the interface. Now, this is the trimmed
implementation of the service class.
#Autowired
private ExRepository exRepository;
#Overrride
public TitleOfMyDb createExampleMethod(String a, String b){
TitleOfMyDb titleOfMyDb = new TitleOfMyDb();
titleOfMyDb .setA(a);
titleOfMyDb .setB(b);
return exRepository.save(titleOfMyDb) //save method is originated from Repository instinctively.
In my (4.)Controller package, i have a class which is ExController:
#Autowired
private ExService exService;
#GetMapping("/test")
public TitleOfMyDb createSomething
(#RequestParam(value="aa") String a, #RequestParam(value="bb") String b){
TitleOfMyDb object = exService.createExampleMethod(a, b)
return object;
}
In my (2.)Repository package, I do not add more codes there, it's kept originally as well. because it already has the instinctive method that allows me to save() my entity with the repository.
Afterwards, when I try to run my spring boot, it shows error of ORA-00942. Also, when I type http://localhost:8080/test through my browser, I can only see nothing but error. The error message was quite complex, sorry that I really cannot copy-paste it through my device. Basically, it does not connect to my db properly.
Any help or guide on my logic and thinking process is really appreciated. Thank you!!!
ORA-00942: table or view does not exist
"You tried to execute a SQL statement that references a table or view that either does not exist, that you do not have access to, or that belongs to another schema and you didn't reference the table by the schema name."
I'd see if the database table is correct and double check the SQL query.
Ref: https://www.techonthenet.com/oracle/errors/ora00942.php
Error mean you don't have permision or your table incorrect. Please check entity. Make sure table : TitleOfMyDb exist in database. If you don't specific table with anotation #table hibernate automatic pick your name entity TitleOfMyDb

Working with POJO classes as schema for mongo db, specifically handling schema changes

I'm using simple Java classes which are the schema for my mongo db table.
There are several frameworks for serialization/ deserialization to/ from JSON and CRUD operations for mongo (I've looked into Jackson serializer and Morphia).
But none of them seems to provide a solution for handling changes:
Let's say I have this class as my schema:
Class Person
{
String name;
int age;
String occupation;
}
In my code, I will probably use a setter in some place for age:
Person newDbEntry = new Person();
newDbEntry.setAge(45);
newDbEntry.setOccupation("Carpenter");
Now let's say that at some point of the development process, it was decided that age field name needs to be changed to "theAge", and it was also decided to remove "occupation" field from this collection completely- to a new table.
The problem that I'm faced with is that all my queries look like this:
JsonObject query = new JsonObject().put("age",new JsonObject().put("$gte", 22);
In other words, all field names are written in queries as Strings (and also in all other mongo APIs- update, findAndModify, etc).
I'm looking for a way to "bind" all mentions of the field "age" in my code with the POJO class- so that when something in the POJO schema changes (like renaming this field), I'll have (ideally) compiler errors in all queries that mention this field.
As it currently stands, changes to schema cause no compiler errors and - more critically - usually no runtime errors. The old string query just quietly returns no results, or something similar. This makes changes to the schema very hard to implement.
How should this be done correctly?
Here's the solution that I ended up using:
Project lombok now supports FieldNames generation:
https://projectlombok.org/features/experimental/FieldNameConstants
So instead of using the name hardcoded as string:
serviceRepository.setField(id, “service.serviceName”, “newName”);
I use:
serviceRepository.setField(id, ConnectivityServiceDetails.Fields.service + "." + ConnectivityService.Fields.serviceName, “newName”);
This way, when we search in Intellij for usages of this field (or try to refactor it), it will find those places also automatically.

How do I configure JPA table name at runtime?

I have an issue where I have only one database to use but I have multiple servers where I want them to use a different table name for each server.
Right now my class is configured as:
#Entity
#Table(name="loader_queue")
class LoaderQueue
I want to be able to have dev1 server point to loader_queue_dev1 table, and dev2 server point to loader_queue_dev2 table for instance.
Is there a way i can do this with or without using annotations?
I want to be able to have one single build and then at runtime use something like a system property to change that table name.
For Hibernate 4.x, you can use a custom naming strategy that generates the table name dynamically at runtime. The server name could be provided by a system property and so your strategy could look like this:
public class ServerAwareNamingStrategy extends ImprovedNamingStrategy {
#Override
public String classToTableName(String className) {
String tableName = super.classToTableName(className);
return resolveServer(tableName);
}
private String resolveServer(String tableName) {
StringBuilder tableNameBuilder = new StringBuilder();
tableNameBuilder.append(tableName);
tableNameBuilder.append("_");
tableNameBuilder.append(System.getProperty("SERVER_NAME"));
return tableNameBuilder.toString();
}
}
And supply the naming strategy as a Hibernate configuration property:
<property
name="hibernate.ejb.naming_strategy"
value="my.package.ServerAwareNamingStrategy"
/>
I would not do this. It is very much against the grain of JPA and very likely to cause problems down the road. I'd rather add a layer of views to the tables providing unified names to be used by your application.
But you asked, so have some ideas how it might work:
You might be able to create the mapping for your classes, completely by code. This is likely to be tedious, but gives you full flexibility.
You can implement a NamingStrategy which translates your class name to table names, and depends on the instance it is running on.
You can change your code during the build process to build two (or more) artefacts from one source.

In Spring Data is it possible to delete entities using an entity's unique attribute?

Is it possible to delete entities using an entity's unique attribute?
In Spring Data 1.4.3.RELEASE, adding methods to find by unique attributes is very easy but, I haven't found a way to do it with delete.
In the following code, Spring automagically handles the findByAddress, is there something similar for delete?
Something like void deleteByAddress(String hwAddress);, I have added it to TerminalRepository but it doesn't work.
public Terminal {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#Column(unique=true)
private String hwAddress;
...
}
public interface TerminalRepository extends
CrudRepository<Terminal, Long> {
Terminal findByAddress(String hwAddress);
}
Of course it is possible to find the entity by address and then use the delete(Terminal) method passing the found entity as parameter. But this wouldn't be good in terms of performance as it will be making one unnecessary call to the database database, i.e., one avoidable call to find the object and another one to delete it
I don't think there's anything built-in for that. You'd have to use the custom method support to roll your own:
http://docs.spring.io/spring-data/jpa/docs/1.4.3.RELEASE/reference/html/repositories.html#repositories.custom-implementations
I was facing the same issue. But, when I annotated method in repository interface with #Modifying , it started working. But, I don't know how it started working. Can anybody explain?

Categories