I have a question on using spring cassandra repository for searching query. I have a table with one partition key and one clustering key together as composite primary key. So in the mapping layer, I create a class for PrimanyKey using #PrimaryKeyClass and #PrimaryKeyColumn, then use #PrimaryKey for the mapping class
the table is created with the following cql
CREATE TABLE user_mobile (phonenum text,memberid uuid,gender text,nickname text,photo timeuuid,PRIMARY KEY (phonenum, memberid))
I create a class called PK_UserMobile to act as primary key class
#PrimaryKeyClass
public class PK_UserMobile implements Serializable {
#PrimaryKeyColumn(ordinal = 0, type = PrimaryKeyType.PARTITIONED)
private String phoneNum;
#PrimaryKeyColumn(ordinal = 1, type = PrimaryKeyType.CLUSTERED)
private UUID memberId;
......
}
and my mapping class is something like this
#Table("user_mobile")
public class UserMobile extends BaseDto {
#PrimaryKey
private PK_UserMobile pk;
........
}
and it is fine to run cql like "select * from user_mobile where phonenum = 'xxxxxxxxx' ;". So I guess it is fine for search this table with partition key only. When I try to search using spring cassandra repository, seems it require me to provide both phonenum's and memberid's value for searching usage. the following exception is thrown if I only set up the value for phonenum.
"com.datastax.driver.core.exceptions.InvalidQueryException: Invalid null value in condition for column memberid. "
So I wanna know if any special null object should I pass in the clustering key as a searching condition? or should I do it in any other way? Thank you.
This is probably because of that you use the standard CRUD repository function findById. To solve the problem, declare a query method on your repository with the following pattern:
findBy{key class name}{property of the key class}
in your case your query method is:
List<UserMobile> findByPK_UserMobilePhoneNum(String phoneNum);
You can use the following way to accomplish this.
No need for a separate PrimaryKeyClass
#Table("user_mobile")
public class UserMobile extends BaseDto {
#PrimaryKeyColumn(ordinal = 0, type = PrimaryKeyType.PARTITIONED)
private String phoneNum;
#PrimaryKeyColumn(ordinal = 1, type = PrimaryKeyType.CLUSTERED)
private UUID memberId;
........
}
Now, define the repository using MapIdCassandraRepository
#Repository
public interface UserMobileRepository extends MapIdCassandraRepository<UserMobile> {
#Query("SELECT * from user_mobile where phoneNum=?0")
List<UserMobile> findByPhoneNum(String phoneNum);
}
This will work!
Related
I have a repository class that calls jdbcTemplate query() and uses BeanPropertyRowMapper(..)
#Override
public List<Model> query(final Model model) {
return this.jdbcTemplate.query(
this.QUERY.replace("${WHERE}", this.queryBuilder.build(model)),
new PostGrePropertyMapper(model)
.addProperty("test", new TestMapper().apply(model.getTest())),
new BeanPropertyRowMapper<>(Model.class));
}
Say I have this model (it has many fields but for demo shortened to 3):
public class Model {
private String test;
private String id;
private String reference;
}
and the query returns me two columns: test & id in the ResultSet.
Is there a way I can set the value of the reference field to that of id that is being returned from database? The id and reference should be set off the id field coming from DB.
Where can I set this value for reference without having to write a custom row mapper and setting each and every field with rs.getString(...) calls.
Is there a short technique for such scenario?
The shortest technique is to fix the query so that it matches the model:
SELECT test, id, id as reference FROM ...
my java code like this:
public class Monitorlog{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
int id;//pk
String sn; // unique constraints(sn,checkpoint)
String checkpoint;
}
public interface MonitorlogDao extends JpaRepository<Monitorlog, Integer>{}
#Service
public class MonitorlogService{
#Autowired
MonitorlogDao monitorlogDao;
public MonitorlogDao getMonitorlog(){
return monitorlogDao;
}
}
The test is like this:
public void testMonitorlogSerivce(){
Monitorlog m = new Monitorlog();
m.setSn("aa");
m.setCheckpoint("bb");
monitorlogService.getMonitorlogDao().save(m);
m = new Monitorlog();
m.setSn("aa");
m.setCheckpoint("bb");
// SQL insert failed here
try{
monitorlogService.getMonitorlogDao().save(m);
}catch(Exception e){
log("",e);
}
}
The secode save(m) is failed , it would like throw a exception, but not.
the m.getId() is 0, but no exception catched, why?
I use sprint boot ver 2.0.0M.
UNIQUE INDEX
CREATE UNIQUE INDEX [IND_IDNO_POSITIONKIND_CHECKPOINT_1] ON
[dbo].[MONITORLOG] ([CHECKPOINT] DESC, [SN] ASC)
WITH (IGNORE_DUP_KEY = ON)
Your provided data on second save violates the PK and/or UK rules of DB.
Always you have to give valid data which will comply the PK and/or UK(unique key) rules to persist in DB for your code.
I got a graph which is described by the following Cypher expression:
CREATE
(BMW:Brand {name: "BMW", country: "Germany"}),
(X3:Model {name: "X3", acceleration: 7.1, maxSpeed: 227.5, displacement: 1997, consumption: 6}),
(lastGen:Generation {from: 2013}),
(xDrive20i:Modification {name: "xDrive20i", maxSpeed: 210, acceleration: 8.3, consumption: 7.9}),
(X3)-[:MODEL_OF]->(BMW),
(BMW)-[:MODEL]->(X3),
(lastGen)-[:GENERATION_OF]->(X3),
(X3)-[:GENERATION]->(lastGen),
(xDrive20i)-[:MODIFICATION_OF]->(X3),
(X3)-[:MODIFICATION]->(xDrive20i),
(lastGen)-[:MODIFICATION]->(xDrive20i),
(xDrive20i)-[:MODIFICATION_OF]->(lastGen);
I described a java class matching to Brand's data structure:
#NodeEntity
#TypeAlias("Brand")
public class Brand {
#GraphId
private Long id;
#Indexed(indexType = IndexType.FULLTEXT, indexName = "brand_name")
private String name;
private String origin;
private String owner;
#RelatedTo(type = "MODEL", direction = Direction.OUTGOING)
private Set<Model> models;
//getters and setters are ommited
}
and repository:
public interface BrandRepository extends GraphRepository<Brand>{
//method's signatures are ommited
}
When I call brandRepository.count() it returns 1 as I expect. But if I call brandRepository.getOne(2249L) I get an exception:
java.lang.IllegalStateException: No primary SDN label exists .. (i.e one with starting with __TYPE__)
As I understand reading LabelBasedNodeTypeRepresentationStrategy source, a node has to have at least one label with __TYPE__ prefix.
How do I map the entity to the graph given that I may not change the graph structure?
I wouldn't mind implementing my own custom LabelBasedNodeTypeRepresentationStrategy if there is no other way. But in this case could somebody let me know why it is implemented this way (I think it is not accidentally) and how should I bind custom solution to spring-data-neo4j use it?
I use neo4j-2.0.0-M06 and spring-data-neo4j-3.0.0.M1.
SDN adds additional metadata to your graph when you store entities, that metadata is missing in your case.
You can try to add that metadata yourself by calling
neo4jTemplate.postEntityCreation(node, Brand.class);
but that for instance doesn't index your name field (manual legacy index).
I was unable to read the full inherited class instances as described in following URL
http://www.datanucleus.org/products/datanucleus/jdo/orm/inheritance.html
Following describes the mapping of classes.
#PersistenceCapable(detachable = "true")
#Discriminator(strategy=DiscriminatorStrategy.CLASS_NAME)
#Inheritance(strategy=InheritanceStrategy.NEW_TABLE)
public class IdeaItem {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
#Column(jdbcType = "INTEGER", length = 11)
private long id;
#Column(name="IDEAID")
private Idea idea;
#Column(jdbcType = "INTEGER", length = 11)
private long showOrder;
}
#PersistenceCapable(detachable = "true")
#Inheritance(strategy=InheritanceStrategy.NEW_TABLE)
public class IdeaItemText extends IdeaItem {
#Column(jdbcType = "VARCHAR", length = 500)
private String text;
}
Data saving part working fine. I inserted "IdeaItemText" object and both "IdeaItem" and "IdeaItemText" tables got updated successfully.
Now I need to read Subclasses by putting "IdeaItem" as an Extent. I executed the following code.
Extent items = getPersistenceManager().getExtent(IdeaItem.class,true);
javax.jdo.Query q = getPersistenceManager().newQuery(items);
List data = (List)q.execute();
As in the JDO docs, this should return the whole object graph. But this is not returning any record. When I check the log, I found that it searching for a reacord where Discriminator Value equals to "com.mydomain.IdeaItem" which does not exists. When I removed the Discriminator annotation I got all the records in the table. Even though how I access the sub classes attributes ? Furthermore how I query subclass attributes with the base class Extent ?
So you didn't let the persistence mechanism know about the subclass (whether that is using auto-start mechanism, persistence.xml, calling pm.getExtent on the subclass, or simply instantiating the subclass.class). It can only query classes that it is "aware of"
I have a class which is mapped to a table using the hibernate notations of auto increment. This class works fine when I set values and update this to the database and I get a correct updated value in the table.
But the issue is when I create a new object of this class and try to get the id, it returns me a 0 instead of the auto_incremented id.
The code of the class is
#Entity(name="babies")
public class Baby implements DBHelper{
private int babyID;
#Id
#Column(name="babyID", unique=true, nullable= false)
#GeneratedValue(strategy = GenerationType.AUTO)
public int getBabyID() {
return babyID;
}
public void setBabyID(int babyID) {
this.babyID = babyID;
}
}
The code I use to get the persistent value is
Baby baby = new Baby();
System.out.println("BABY ID = "+baby.getBabyID());
This returns me a
BABY ID = 0
Any pointers would be appreciated.
Thanks,
Sana.
Hibernate only generates the id after an entity becomes persistent, ie after you have saved it to the database. Before this the object is in the transient state. Here is an article about the Hibernate object states and lifecycle
The ID is set by hibernate when object is saved and became persistable.
The annotation are only informing hibernate, how he should behave with class, property, method that annotation refer to.
Another thing if You have current id value how hibernate, would be able to recognize that he should insert or only update that value.
So this is normal expected behavior.