I'm using ObjectDB with JPA. I would like to call myMethod(). For example:
entityManager.createQuery("SELECT ... FROM ... WHERE MyClass.myMethod() = 100")
Is it possible? Maybe any annotation is required before method in the class?
#Entity
public class MyClass implements Serializable {
#Basic
private int x;
#Basic
private int y;
public int myMethod() {
return x*1000+y;
}
}
JPQL is not exactly an object-based query language. You can't define your own methods, and JPQL provides a very limited set of functions. So if you want to keep within the JPA spec then the answer is no; would have to be JPA-implementation specific - DataNucleus JPA certainly allows you to have your own methods in the query language (as a vendor extension), no idea about your quoted JPA provider - that said though, it would only execute such a query in the datastore if you put the code for that method in a query method implementation (as opposed to in the class)
Yes, you can! And no additional annotations are required.
ObjectDB is an implementation of an object-oriented database system (OODBS) and as a result allows you to interact with database items as objects, that includes calling methods, using inheritance and polymorphism, etc.
This is a simple working example I have. With a class like this:
#Entity
public class Person {
private static final long serialVersionUID = 1L;
#Id #GeneratedValue
private long id;
private String firstName;
private String lastName;
Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFullName() {
return firstName + " " + lastName;
}
}
This query returns correct results:
entityManager.createQuery(
"SELECT p FROM Person p WHERE p.getFullName()='John Johnson'", Person.class).getResultList();
JPQL is translated into SQL, so you cannot include a Java method call, as your database (most likely) does not support Java.
In JPA 2.1 you will be able to use the FUNCTION operator to call "database" functions. Some database do support defining functions in Java, but normally a proprietary database language is used (such as PL/SQL).
EclipseLink supports both FUNC and FUNCTION operators for calling database functions. You can also define your own operators using the OPERATOR operator which allows you to define your own custom database function call in Java.
http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/JPQL#EclipseLink_special_operators
Not the way you are looking for. If you want to use custom method, you can create and register them before using them.
e.g. create a function as below:
public int myMethod(int x, int y){
return x*1000+y;
}
Then register this function using registerFunction() with the dialect of your database. Once done, you can write a query as :
from MyClass data where myMethod(data.x, data.y) =100;
Hoe this helps.
No you can't do that. Since JPA always works with prepared statement (parameterized SQL), you can only set parameters in the WHERE clause of the JPQL query like
entityManager.createQuery("SELECT .... FROM ... WHERE
someCondition=:someValue).setParameter("someValue", "parameterValue");
Make the method (myMethod()) return that value somehow and replace the second parameter which is parameterValue of the setParameter() method by the value returned by your method, myMethod().
Related
Let say I have the following entity, (I skip the constructor for simplicity):
public class Person {
int id;
String name;
String lastName;
Date birthday;
List<Vehicles> vehicles;
}
And I want to create a DTO in order to get only what I need from the DB:
public class PersonDTO {
int id;
String name;
List<Vehicles> vehicles;
}
My Crud repository looks like this:
Person findById(int personId);
But I want to change it to:
PersonDTO findById(int personId);
It works perfectly if I remove the vehicles property, (is a List), but I do need this list. Any clue?
Citing the Spring Data JPA reference:
Another way of defining projections is by using value type DTOs (Data Transfer Objects) that hold properties for the fields that are supposed to be retrieved. These DTO types can be used in exactly the same way projection interfaces are used, except that no proxying happens and no nested projections can be applied.
Your List<Vehicles> vehicles is a nested projection, so your apporach is not applicable. You need to make use of an interface-based projection in this case:
public interface PersonProjection {
int getId();
String getName();
List<VehicleProjection> getVehicles();
interface VehicleProjection {
// Getters for desired fields of Vehicle as above for Person(Projection)
}
}
Then you can change your repository method to
PersonProjection findById(int personId);
Unfortunately, the interface-based approach is slightly less performant because, as the reference documentation states, proxying happens.
I am trying to use spring-data to replace our current usage of POJO to Document with mongodb, in this particular case instead of using a field as Id for the entity I use some fields.
For example, if I have this pojo:
class Thing {
public String firstName;
public String lastName;
public Int age;
}
At the moment to save it to mongodb I first do a conversion to Document:
Document doc = new Document();
doc.append("firstName", thing.firstName);
doc.append("lastName", thing.lastName);
doc.append("age", thing.age);
Then I create a query:
BasicDBObject query = new BasicDBObject(
and(
new BasicDBObject("firstName", thing.firstName),
new BasicDBObject("lastName", thing.lastName))
And then I upsert the doc using mongodb driver.
collection.updateOne(query, document, UpdateOptions().upsert(true))
This way I get the age updated only and do not need to bother about the ObjectId that there is no meaning for me.
Now I want to change it to spring-data-mongodb to be less error prone when writing the document conversion part and be more productive. But I could not find how to do something similar with spring-data-mongodb, the save in MongoRepository api is base in the ObjectId and I can not find any annotation or bean to override/create to let me do something like this.
In a perfect world I would have something like a composite key for spring-data-mongodb. So for instance I would have to just write my POJO this way:
class Thing {
#Id public String firstName;
#Id public String lastName;
public Int age;
}
Or (not the better case but maybe acceptable)
class ThingKey {
public String firstName;
public String lastName;
}
class Thing {
#Id public ThingKey thingKey;
public Int age;
}
And the save would be able to figure out that this is a upsert to a existing entity and do act with this regards.
PS: The POJOs here are simplified versions to help understand the problem and are not the final version that I am using.
There is a section on "upserting" in the official docs. It looks like you have to use either the upsert() or findAndModify() on MongoTemplate.
Alternatively, you could just do a find(), perform your changes to the object that is returned, and then do a save().
Currently I use a lot of queries which use constructors for building value objects in JPQL as below
#Query("SELECT new com.DocDTO(d.documentId, d.docType) FROM Document d where d.parentId=:parentId")
Set<DocDTO> getDocsWithinFolder(#Param("parentId") Long parentId);
But as code gets complex, I have a need to build objects with various combinations of constructor parameters, leading to the classic telescoping problem.
As explained in Effective Java (Item1) is there a way to build a JPQL query by passing a factory method instead of a constructor ? I am thinking something along the lines of
#Query("SELECT DocDTO.query1(d.documentId, d.docType) FROM Document d where d.parentId=:parentId")
Set<DocDTO> getDocsWithinFolder(#Param("parentId") Long parentId);
and then build the appropriate static factory method query1 inside the DocDTO class. Is this possible in JPQL ?
You can use Dynamic projection to solve this problem. Dynamic projection let you to change return type of single query dynamically. To better understand this lets take a example of this User entity:
#Entity
public class User {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String firstName;
private String lastName;
private String email;
// setter and getters
}
If you want to get only name of a user using dynamic projection first you will need to create a interface like this:
public interface Name {
String getLastName();
String getFirstName();
}
In your repository you will need to create query like this:
<T> List<T> findByLastName(String lastName, Class<T> type);
or with #Query
#Query("select u.firstName,u.lastName from User u where lastName=?1")
<T> List<T> findByLastName(String lastName,Class<T> type);
In your service:
List<Name> name = findByLastName("xyz",Name.class);
I am beginner on Neo4j , I want to convert Spring data query to Neo4j Query.
I have three tables.
#RelationshipEntity(type = "IS_ATTENDING_EVENT")
public class IsAttendingEventDO {
#GraphId
private Long id;
#Property
private String isAttendingEventId;
#StartNode
private PersonDO personDO = new PersonDO();
#EndNode
private EventDO eventDO = new EventDO();
#NodeEntity(label="Person")
public class PersonDO {
#GraphId Long id;
#Property
private String personId;
#Property
private String name;
#NodeEntity(label="Event")
public class EventDO {
#GraphId
private Long id;
#Property
private String eventId;
Here is my spring-data query.
IsAttendingEventDO getByEventEventIdAndPersonPersonId(String eventId, String personId);
Please help me to convert this query to Neo4j query.
Regards,
Parth Solanki.
I think you should read through the Neo4j developers manual and get an understanding of Cypher syntax and usage.
With basic understanding of Cypher, it's a very simple query. Just match on the pattern you are interested in (a person attending an event, using the labels already defined), provide variables on the person, the event, and the relationship, add a WHERE clause to restrict the person and the event in the match to the given id parameters, then return the relationship that fits the matched pattern where those predicates apply:
MATCH (p:Person)-[rel:IS_ATTENDING_EVENT]->(e:Event)
WHERE p.id = {personId} AND e.id = {eventId}
RETURN rel
EDIT:
Answering your comment about returning the list of relationships (of a :Person attending an :Event) where the only given parameter is the eventId.
To form lists from nodes, you can use the COLLECT() function.
So if you're trying to get the relationships based only on an eventId, you don't need to supply a variable on the :Person node, as you don't have any predicate to apply to it, and you aren't using it or returning it. All you're interested in are relationships of people attending the event with the given eventId, and returning the collection of those returned relationships.
MATCH (:Person)-[rel:IS_ATTENDING_EVENT]->(e:Event)
WHERE e.id = {eventId}
RETURN COLLECT(rel)
Again, please read through the developers manual, and also use the Cypher refcard to help you out. The kind of questions you're asking are very easily done when you have read through the basic documentation.
#Entity
public class Language {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(length = 2)
private String code; //EN, DE, US
public Language(String code) {
this.code = code;
}
}
#Entity
public class ProductText {
#OneToOne(Cascade.ALL)
private Language lang;
}
ProductText text = new ProductText();
text.setLang(new Language("en")); //what if "en" exists?
dao.save(text);
Now, when I persist the ProductText, everytime a new Language object would be generated.
Can I prevent this, and in case a language table entry with code = 'en' exists this existing entity should be linked instead.
My initial goal is to not having to repeat the countryCodeString "EN" multiple times in my product-text table, but just reference the id. But does this really make sense? Should I rather just use the plain String without an extra table? (I later want to query a list of productTexts where lang = 'de').
Is the only change executing a select like dao.findByLang("en") before?
Or is there also some hibernate feature that would support this without explicit executing a query myself?
Do you process the value "en" further or do you display it directly? If only used for displaying purposes, I would just store the string, but if you want to reduce redundancy by using foreign key IDs you have to create an Entity containing the language string en which can be persisted via entity manager and which you have to obtain out of the entity manager before persisting to reuse it.
If there is only three different possible values for the language, you can also use an enum like thisĀ :
public enum Language {
EN("EN"),
DE("DE"),
US("US");
private String code; //EN, DE, US
public Language(String code) {
this.code = code;
}
// Getter...
}
#Entity
public class ProductText {
#Enumerated(EnumType.STRING)
// Or #Enumerated(EnumType.ORDINAL)
private Language lang;
}
EnumType.STRING will store the enum in the database as a String, while EnumType.ORDINAL will store it as an int. Int is maybe a little more efficient, but the mapping could change if you insert a new value in your enum. String is more flexible since it will use the names of your enum members.
In both case, you don't have to manage a separate entity and hibernate will not create an additional table, and it's more type-safe than using a plain string.
If the only value in Language is a 2 or 3 letter string, why not just have the string as a member? This will be quicker and more efficient.