JPQL: The state field path cannot be resolved to a valid type - jpql

I can't make this query work:
Query query = eManager.createQuery("select c FROM News c WHERE c.NEWSID = :id",News.class);
return (News)query.setParameter("id", newsId).getSingleResult();
and I got this exception:
Exception Description: Problem compiling [select c FROM News c WHERE c.NEWSID = :id].
[27, 35] The state field path 'c.NEWSID' cannot be resolved to a valid type.] with root cause
Local Exception Stack:
Exception [EclipseLink-0] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.JPQLException
Exception Description: Problem compiling [select c FROM News c WHERE c.NEWSID = :id].
Why does it happen?
:id and named parameter are identical
EDIT:
my entity class
#Entity
#Table(name="NEWS")
public class News implements Serializable{
#Id
#SequenceGenerator(name = "news_seq_gen", sequenceName = "news_seq")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "news_seq_gen")
private int newsId;
private String newsTitle;
private String newsBrief;
private String newsContent;
private Date newsDate;
#Transient
private boolean selected=false;
//constructor and getters and setters

That happens because News entity does not have persistent attribute named NEWSID. Names of the persistent attributes are case sensitive in JPQL queries and those should be written with exactly same case as they appear in entity.
Because entity have persistent attribute named newsId, that should also be used in query instead of NEWSID:
select c FROM News c WHERE c.newsId = :id

entity have persistent attribute named newsId.but in query you have used NEWSID . try with this
select c FROM News c WHERE c.newsId = :id

My entity is:
#Entity
#Table(name = "TBL_PERSON_INFO")
public class Person implements Serializable {
#Id
#Column(name = "ID", nullable = false)
private Integer id;
#Column(name = "USER_ID", nullable = false)
private Integer user_id;
.
.
.
}
my query is (JPQL):
String queryName = "from Person p where p.user_id = :user_id";
so I use it like this:
javax.persistence.Query query = em.createQuery(queryName);
query.setParameter("user_id", userId);
try {
obj = query.getSingleResult();
}
catch (javax.persistence.NoResultException nre) {
logger.error("javax.persistence.NoResultException: " + nre.getMessage());
}
catch (javax.persistence.NonUniqueResultException nure) {
logger.error("javax.persistence.NonUniqueResultException: " + nure.getMessage());
}
catch (Exception e) {
e.printStackTrace();
}
if (obj == null) {
System.out.println("obj is null!");
return null;
}
Person person = (Person) obj;
It's work ;-)

Related

Datastax mapper complains about duplicate columns in generated insert statement

Versions: Datastax Java driver 3.1.4, Cassandra 3.10
Consider the following table:
create table object_ta
(
objid bigint,
version_date timestamp,
objecttype ascii,
primary key (objid, version_date)
);
And a mapped class:
#Table(name = "object_ta")
public class ObjectTa
{
#Column(name = "objid")
private long objid;
#Column(name = "version_date")
private Instant versionDate;
#Column(name = "objecttype")
private String objectType;
public ObjectTa()
{
}
public ObjectTa(long objid)
{
this.objid = objid;
this.versionDate = Instant.now();
}
public long getObjId()
{
return objid;
}
public void setObjId(long objid)
{
this.objid = objid;
}
public Instant getVersionDate()
{
return versionDate;
}
public void setVersionDate(Instant versionDate)
{
this.versionDate = versionDate;
}
public String getObjectType()
{
return objectType;
}
public void setObjectType(String objectType)
{
this.objectType = objectType;
}
}
After creating a mapper for this class (mm is a MappingManager for the session on mykeyspace)
final Mapper<ObjectTa> mapper = mm.mapper(ObjectTa.class);
On calling
mapper.save(new ObjectTa(1));
I get
Query preparation failed: INSERT INTO mykeyspace.object_ta
(objid,objid,version_date,objecttype) VALUES (?,?,?,?);:
com.datastax.driver.core.exceptions.InvalidQueryException: The column
names contains duplicates at
com.datastax.driver.core.Responses$Error.asException(Responses.java:136)
at
com.datastax.driver.core.SessionManager$4.apply(SessionManager.java:220)
at
com.datastax.driver.core.SessionManager$4.apply(SessionManager.java:196)
at
com.google.common.util.concurrent.Futures$ChainingListenableFuture.run(Futures.java:906)
at
com.google.common.util.concurrent.Futures$1$1.run(Futures.java:635)
at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at
io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
at java.lang.Thread.run(Thread.java:745)
I am at a loss to understand, why the duplicate objid is generated in the query.
Thank you in advance for pointers to the problem.
Clemens
I think it is because the inconsistent use of case on the field name (objid) vs the setter/getters (getObjId). If you rename getObjId and setObjId to getObjid and setObjid respectively, I believe it might work.
In a future release, the driver mapper will allow the user to be more explicit about whether setters/getters are used (JAVA-1310) and what the naming conventions are (JAVA-1316).

Cassandra UDT mapping issue

I am not able to map data which has UDT type.
The table is definition is the following.
CREATE TABLE IF NOT EXISTS members_data.Test(
priority int,
name text,
test_links list<frozen<TestLinks>>,
PRIMARY KEY(name)
);
The model is the following.
#JsonAutoDetect
#JsonSerialize
#Table(keyspace="members_data", caseSensitiveKeyspace=false, caseSensitiveTable=false, name="Test")
public class Test{
#Column(name="name", caseSensitive=false)
private String name;
#Column(name="priority", caseSensitive=false)
private int priority;
#Frozen
#Column(name="test_links", caseSensitive=false)
private List<TestLinks> test_links;
#JsonAutoDetect
#JsonSerialize
#UDT(keyspace = "members_data", name = "Testlinks")
public class TestLinks {
#Field(name = "test_link")
private String test_link;
#Field(name = "link_title")
private String link_title;
The mapper usage.
MappingManager manager = new MappingManager(sessionManager.getSession());
manager.udtCodec(TestLinks.class);
Mapper<Test> mapper = manager.mapper(Test.class);
Result<Test> result = mapper.map(testResultSet);
test = result.one(); //test object would be null here
the cassandra-driver-mapping is 3.1.0.
Mapper is not throwing any error and now even mapping data to model. Could someone tell me what is the problem?

JPQL, Where condition on Set with List of values

#Entity
public class Person{
private String firstName;
private String lastName;
#OneToMany(mappedBy="person" , fetch= FetchType.LAZY)
private Set<Certificate> certificates;
}
#Entity
public class Certificate{
private String courseName;
#ManyToOne
#JoinColumn(name="person_id")
private Person person;
}
Having an entity class(Person), which holds a collection(Set) of related entities(Certificate) mapped using #OneToMany as above.
Now I have to fetch all Persons having certificate.courseName IN ("OCPJP", "OCPWCD").
In Simple SQL, My query will be like this.
select distinct p.firstName, p.lastName from Person p join Certificate c on p.Id = c.person_Id
where c.courseName IN ("OCPJP", "OCPWCD")
How to get similar output in JPQL?
Such a query can be written as follows:
SELECT DISTINCT(c.person) FROM Certificate c WHERE c.courseName IN (:coursenames)
Complete example:
List<String> courseNames = Arrays.asList("OCPJP", "OCPWCD");
List<Person> result = em.createQuery(
"SELECT DISTINCT(c.person) " +
"FROM Certificate c " +
"WHERE c.courseName IN (:coursenames)", Person.class)
.setParameter("coursenames", courseNames)
.getResultList();

JPQL Query - get child item in list from a parent

How would I create a JPQL query to get a Record if it exists in a Folder when I have the Folder :id and the Record :refId (named parameters). I would like to have the Record returned back from the query as there is other data that is part of the Record needed.
Here are the entities:
#Entity
public class Folder {
#Id
#Column(name = "id")
private Long id;
#OneToMany(targetEntity = Record.class, cascade = { CascadeType.ALL })
#JoinColumn(name = "RECORD_FOLDER_0")
#OrderBy("id ASC")
private List<Record> records;
...
}
#Entity
public class Record {
#Id
#Column(name = "id")
private Long id;
#Basic
#Column(name = "refId")
private Long refId;
#Basic
#Column(name = "data", length = 255)
private String data;
...
}
The regular SQL would look something like:
.createNativeQuery(String.format("SELECT * FROM record r WHERE r.refId=%d AND r.RECORD_FOLDER_0=%d", refId, folderId));
I am struggling on how to use a JPQL query to do this.
Since you don't have a reference to the parent Folder from Record, you'll have to start with the Folder and join the child Records. Something like this should do the trick:
TypedQuery<Record> q = em.createQuery(
"SELECT r FROM Folder f JOIN f.records r " +
"WHERE f.id = :folderId AND r.refId = :refId", Record.class);
q.setParameter("folderId", folderId);
q.setParameter("refId", refId);

How to execute ranged query in cassandra with astyanax and composite column

I am developing a blog using cassandra and astyanax. It is only an exercise of course.
I have modelled the CF_POST_INFO column family in this way:
private static class PostAttribute {
#Component(ordinal = 0)
UUID postId;
#Component(ordinal = 1)
String category;
#Component
String name;
public PostAttribute() {}
private PostAttribute(UUID postId, String category, String name) {
this.postId = postId;
this.category = category;
this.name = name;
}
public static PostAttribute of(UUID postId, String category, String name) {
return new PostAttribute(postId, category, name);
}
}
private static AnnotatedCompositeSerializer<PostAttribute> postSerializer = new AnnotatedCompositeSerializer<>(PostAttribute.class);
private static final ColumnFamily<String, PostAttribute> CF_POST_INFO =
ColumnFamily.newColumnFamily("post_info", StringSerializer.get(), postSerializer);
And a post is saved in this way:
MutationBatch m = keyspace().prepareMutationBatch();
ColumnListMutation<PostAttribute> clm = m.withRow(CF_POST_INFO, "posts")
.putColumn(PostAttribute.of(post.getId(), "author", "id"), post.getAuthor().getId().get())
.putColumn(PostAttribute.of(post.getId(), "author", "name"), post.getAuthor().getName())
.putColumn(PostAttribute.of(post.getId(), "meta", "title"), post.getTitle())
.putColumn(PostAttribute.of(post.getId(), "meta", "pubDate"), post.getPublishingDate().toDate());
for(String tag : post.getTags()) {
clm.putColumn(PostAttribute.of(post.getId(), "tags", tag), (String) null);
}
for(String category : post.getCategories()) {
clm.putColumn(PostAttribute.of(post.getId(), "categories", category), (String)null);
}
the idea is to have some row like bucket of some time (one row per month or year for example).
Now if I want to get the last 5 posts for example, how can I do a rage query for that? I can execute a rage query based on the post id (UUID) but I don't know the available post ids without doing another query to get them. What are the cassandra best practice here?
Any suggestion about the data model is welcome of course, I'm very newbie to cassandra.
If your use case works the way I think it works you could modify your PostAttribute so that the first component is a TimeUUID that way you can store it as time series data and you'd easily be able to pull the oldest 5 or newest 5 using the standard techniques. Anyway...here's a sample of what it would look like to me since you don't really need to make multiple columns if you're already using composites.
public class PostInfo {
#Component(ordinal = 0)
protected UUID timeUuid;
#Component(ordinal = 1)
protected UUID postId;
#Component(ordinal = 2)
protected String category;
#Component(ordinal = 3)
protected String name;
#Component(ordinal = 4)
protected UUID authorId;
#Component(ordinal = 5)
protected String authorName;
#Component(ordinal = 6)
protected String title;
#Component(ordinal = 7)
protected Date published;
public PostInfo() {}
private PostInfo(final UUID postId, final String category, final String name, final UUID authorId, final String authorName, final String title, final Date published) {
this.timeUuid = TimeUUIDUtils.getUniqueTimeUUIDinMillis();
this.postId = postId;
this.category = category;
this.name = name;
this.authorId = authorId;
this.authorName = authorName;
this.title = title;
this.published = published;
}
public static PostInfo of(final UUID postId, final String category, final String name, final UUID authorId, final String authorName, final String title, final Date published) {
return new PostInfo(postId, category, name, authorId, authorName, title, published);
}
}
private static AnnotatedCompositeSerializer<PostInfo> postInfoSerializer = new AnnotatedCompositeSerializer<>(PostInfo.class);
private static final ColumnFamily<String, PostInfo> CF_POSTS_TIMELINE =
ColumnFamily.newColumnFamily("post_info", StringSerializer.get(), postInfoSerializer);
You should save it like this:
MutationBatch m = keyspace().prepareMutationBatch();
ColumnListMutation<PostInfo> clm = m.withRow(CF_POSTS_TIMELINE, "all" /* or whatever makes sense for you such as year or month or whatever */)
.putColumn(PostInfo.of(post.getId(), post.getCategory(), post.getName(), post.getAuthor().getId(), post.getAuthor().getName(), post.getTitle(), post.getPublishedOn()), /* maybe just null bytes as column value */)
m.execute();
Then you could query like this:
OperationResult<ColumnList<PostInfo>> result = getKeyspace()
.prepareQuery(CF_POSTS_TIMELINE)
.getKey("all" /* or whatever makes sense like month, year, etc */)
.withColumnRange(new RangeBuilder()
.setLimit(5)
.setReversed(true)
.build())
.execute();
ColumnList<PostInfo> columns = result.getResult();
for (Column<PostInfo> column : columns) {
// do what you need here
}

Resources