I have a table
Customer(Name ,Gender,State,age,city)
I want to filter my customer table by a combination of
(gender,state,city,age)
User can either enter any one,two,three or four filter criteria. I am stuck at writing the criteria query for this How can I do this??
package com.thoughtclan.segmentationofcustomers.specification;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.springframework.data.jpa.domain.Specification;
import com.thoughtclan.segmentationofcustomers.model.Customer;
public class FilterCriteria implements Specification<Customer> {
private SearchCriteria criteria;
#Override
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
// TODO Auto-generated method stub
return null;
}
}
Can you Explain in this context??
**
This Is my service class method
**
public Set<Customer> filterDetails(TargetGroupDto targetGroupDto) {
// TODO Auto-generated method stub
}
You should store your filter options in some class. Than just check if they exist and add criteria.
Criteria criteria = session.createCriteria(Customer.class);
// here you receive some DTO with filter fields
if (filter.getState != null) {
criteria.add(Restrictions.eq("state", filter.getState));
}
if (filter.getCity != null) {
criteria.add(Restrictions.eq("city", filter.getCity));
}
criteria.list() // return result
session.close() // or you can use try-with-resources
Edit: As your question is updated later, I already asked you in comment for a JPQL query. So this answer is related with JPQL, not criteria query.
You can do it with JPQL query. I assume that you generate (you can generate if from your IDE ) or create a database entity class named Customer which has the member
private String name;
private String gender;
private String state;
private Integer age;
private String city;
.... setters and getters
Now add the class reference in persistent.xml if not exist.
<class>Customer</class> //if additional package exist then give the package name e.g com.test.Customer
Now come in the query part.
Query q = entityManager.createQuery("SELECT c from Customer c where c.gender=:gender and c.state=:state and c.city=:city and c.age=:age");
q.setParameter("gender", "MALE");//Assume gender value is Male
q.setParameter("state", "Honululu");//Assume state value is Honululu
q.setParameter("city", "abc");//Assume city value is abc
q.setParameter("age", 10);//Assume age value is 10
Object resp = q.getResultList();
Now resp object contains your data. Cast the object to java.util.List to get data.
You can add some logic to combine your query. Suppose you have a business object CustomerBO instance cbo.
if(cbo.getGender()!=null && !cbo.getGender().isEmpty()){
q.setParameter("gender", cbo.getGender());
}
and so many condition as your wish .....
Related
I have a bidirectional 1 to many relation between SelfEmployed and IncomeExpense classes. Suppose I have two different persistent instances of SelfEmployed. I need to copy of some SelfExpense object from one parent and add them to another.
To copy object I just use default constructor to create instance, and then assign only three primitive values, and sets selfEmployed=null instance and id=null.
BUT, when I do the following secondSelfEmployed.getIncomeExpenses().add(incomeExpenseCopy);
Somehow it finds the origin instance of incomeExpense, and sets the rest fields like id and selfEmployed. Thus, when the transaction commits it throws the exception, that I try to add incomeExpense, that already has its parent object selfEmployed
org.datanucleus.exceptions.NucleusUserException: Management of relations : Object "SelfEmployed#6d651cc" has a bidirectional field "incomeExpenses" and the object"IncomeExpense#60942b95" was added to this field, but this field has had its owner set to "SelfEmployed#1fb974bc"!
import java.util.HashSet;
import java.util.Set;
public class SelfEmployed {
protected Set<IncomeExpense> incomeExpenses = new HashSet<IncomeExpense>();
// some primitive fields
public Set<IncomeExpense> getIncomeExpenses(){
return incomeExpenses;
}
// standard getters and setters
}
and
public class IncomeExpense {
protected int year;
protected Double annualGrossTurnover;
protected Double annualExpenses;
protected SelfEmployed selfEmployed;
// standard getters and setters
public void setSelfEmployed(SelfEmployed selfEmployed) {
this.selfEmployed = selfEmployed;
}
public SelfEmployed getSelfEmployed() {
return selfEmployed;
}
}
The following logic is performed within transaction.
The problem is here
for (IncomeExpense ie: selfEmployed1.getIncomeExpenses()){
IncomeExpense copy = new IncomeExpense();
copy.setYear(ie.getYear());
copy.setAnnualGrossTurnover(ie.getAnnualGrossTurnover());
copy.setAnnualExpenses(ie.getAnnualExpenses());
selfEmployed2.getIncomeExpenses().add(copy);// on this line it sets to copy fields id, and selfEmployed, that was in ie
}
I have a use case where in a person can have no. of carts. This is possible because 1) user can complete an order with a cart and after that cart is considered closed 2) user can leave a cart for 2 months and it is considered expired. If user adds new item on 2 months old cart, old cart is marked expired and new cart is generated.
I tried designing following table:
Table Name: Cart
Primary Hash Key: cartId (String)
Primary Range Key: updated (String)
I am using updated as a range column so that when I query it I can get all the carts sorted on when user updated those and I can pick the first (or last) one without sorting myself to have the most recent cart. However this is messing up my use cases.
If a user adds another item, I update the item in the cart and update the updated column as well. However this creates another cart for me (with same cart id but with new updated column). After re-reading the docs, I understand that primary key is composite of cartId and updated so probably I should remove it. However I believe my use case is genuine enough and it is bad that in my case I have to do sorting in application. Another way around would be to use an auto increment as range but that is non intuitive way of putting columns. If there is a work around pls let me know. I am using DynamoDBMapper and posting my classes (with only few fields).
import java.util.Set;
import com.amazonaws.services.dynamodbv2.datamodeling.*;
#DynamoDBTable(tableName="Cart")
public class Cart {
private String cartId;
private String email;
private Set<String> cartItemsJson;
private String status;
private String created;
private String updated;
#DynamoDBHashKey(attributeName="cartId")
public String getCartId() {
return cartId;
}
public void setCartId(String cartId) {
this.cartId = cartId;
}
#DynamoDBAttribute(attributeName="email")
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
#DynamoDBAttribute(attributeName="cartItems")
public Set<String> getCartItemsJson() {
return cartItemsJson;
}
public void setCartItemsJson(Set<String> cartItemsJson) {
this.cartItemsJson = cartItemsJson;
}
#DynamoDBAttribute(attributeName="status")
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
#DynamoDBAttribute(attributeName="created")
public String getCreated() {
return created;
}
public void setCreated(String created) {
this.created = created;
}
#DynamoDBRangeKey(attributeName="updated")
#DynamoDBVersionAttribute(attributeName="updated")
public String getUpdated() {
return updated;
}
public void setUpdated(String updated) {
this.updated = updated;
}
}
This the persistence layer code. I have tried various combinations of Save behaviour but still same results.
protected static DynamoDBMapper mapper = new DynamoDBMapper(dynamoDbClient);
mapper.save(cart,new DynamoDBMapperConfig(DynamoDBMapperConfig.SaveBehavior.UPDATE));
In DynamoDB you can not update the Hash or Range key. Updating them means deleting and create a new entry.
I know that you can create a Secondary index. Maybe this will help.
Also I think you can overcome the updated as range key. You can create the table as follows:
HashKey = userId
RangeKey = cardId ( but cardId needs to be sortable for each user )
normal column = updated
normal column = etc..
When you need the last cardId of a specific user, you can get top 1 rows for a hashkey=your user and reverse sorted so you get the last one first.
When you need to add an item to the card, you don't need to update the hash/range keys.
Hope it helps.
I'm trying to update an entity using Entity Framework version 6.
I'm selecting the entity from the database like so...
public T Find<T>(object id) where T : class
{
return this._dbContext.Set<T>().Find(id);
}
And updating the entity like so..
public T Update<T>(T entity) where T : class
{
// get the primary key of the entity
object id = this.GetPrimaryKeyValue(entity);
// get the original entry
T original = this._dbContext.Set<T>().Find(id);
if (original != null)
{
// do some automatic stuff here (taken out for example)
// overwrite original property values with new values
this._dbContext.Entry(original).CurrentValues.SetValues(entity);
this._dbContext.Entry(original).State = EntityState.Modified;
// commit changes to database
this.Save();
// return entity with new property values
return entity;
}
return default(T);
}
The GetPrimaryKeyValue function is as so...
private object GetPrimaryKeyValue<T>(T entity) where T : class
{
var objectStateEntry = ((IObjectContextAdapter)this._dbContext).ObjectContext
.ObjectStateManager
.GetObjectStateEntry(entity);
return objectStateEntry.EntityKey.EntityKeyValues[0].Value;
}
Just for clarity. I'm selecting the original entry out as I need to perform some concurrency logic (that Ive taken out). I'm not posting that data with the entity and need to select it manually out of the DB again to perform the checks.
I know the GetPrimaryKeyValue function is not ideal if there's more than one primary key on the entity. I just want it to work for now.
When updating, entity framework coughs up the error below when trying to execute the GetPrimaryKeyValue function.
The ObjectStateManager does not contain an ObjectStateEntry with a reference to an object of type 'NAME_OF_ENTITY_IT_CANNOT_FIND'
I've written many repositories before and I've never had this issue, I cannot seem to find why its not working (hence the post).
Any help would be much appreciated.
Thanks guys!
Steve
It seems like you are having issues getting the PK from the entity being passed in. Instead of trying to go through EF to get this data you could either use their Key attribute or create your own and just use reflection to collect what the key names are. This will also allow you to retrieve multiple keys if it is needed. Below is an example I created inside of LinqPad, you should be able to set it to "Program" mode and paste this in and see it work. Hack the code up and use what you may. I implemented an IEntity but it is not required, and you can change the attribute to anything really.
Here are the results:
Keys found:
CustomIdentifier
LookASecondKey
Here is the code:
// this is just a usage demo
void Main()
{
// create your object from wherever
var car = new Car(){ CustomIdentifier= 1, LookASecondKey="SecretKey", Doors=4, Make="Nissan", Model="Altima" };
// pass the object in
var keys = GetPrimaryKeys<Car>(car);
// you have the list of keys now so work with them however
Console.WriteLine("Keys found: ");
foreach(var k in keys)
Console.WriteLine(k);
}
// you probably want to use this method, add whatever custom logic or checking you want, maybe put
private IEnumerable<string> GetPrimaryKeys<T>(T entity) where T : class, IEntity
{
// place to store keys
var keys = new List<string>();
// loop through each propery on the entity
foreach(var prop in typeof(T).GetProperties())
{
// check for the custom attribute you created, replace "EntityKey" with your own
if(prop.CustomAttributes.Any(p => p.AttributeType.Equals(typeof(EntityKey))))
keys.Add(prop.Name);
}
// check for key and throw if not found (up to you)
if(!keys.Any())
throw new Exception("No EntityKey attribute was found, please make sure the entity includes this attribute on at least on property.");
// return all the keys
return keys;
}
// example of the custom attribute you could use
[AttributeUsage(AttributeTargets.Property)]
public class EntityKey : Attribute
{
}
// this interface is not NEEDED but I like to restrict dal to interface
public interface IEntity { }
// example of your model
public class Car : IEntity
{
[EntityKey] // add the attribure to property
public int CustomIdentifier {get;set;}
[EntityKey] // i am demonstrating multiple keys but you can have just one
public string LookASecondKey {get;set;}
public int Doors {get;set;}
public string Make {get;set;}
public string Model {get;set;}
}
I'm getting my feet wet with persistence and Objectify. I'd like some guidance on assigning a Parent key. My specific questions are in all caps. Thanks.
(The sample model below contains an AppUser and a Video. The idea is like YouTube; a user creates videos that belong to him/her.)
#Entity
class Video{
// QUESTION 1: SHOULD THIS CLASS HAVE ONLY 1 KEY FIELD IF I WANT A
PARENT RELATIONSHIP WITH AppUser, AND TYPE IS Key<AppUser> ?
#Parent Key<AppUser> owner;
#Id private Long id;
protected Video(){}
protected Video(User u){ // GAE User object
AppUser au = ofy().load().type(AppUser.class).filter("userId",u.getUserId()).first().get();
// QUESTION 2: WHICH WAY IS RIGHT (TO ASSIGN PARENT KEY)?
this.owner = Key.create(au.getKey(),AppUser.class,au.getId());
// or:
// owner = au.getKey();
// or:
// owner = au;
}
}
#Entity
public class AppUser {
#Id private String userId;
// QUESTION 3: DO ALL CLASSES REQUIRE A KEY FIELD?
private Key<AppUser> key;
protected AppUser(){}
protected AppUser(User u){// GAE User object
this.userId = u.getUserId();
}
public String getId(){
return userId;
}
public Key<AppUser> getKey(){
// QUESTION 4: IS THIS THE CORRECT WAY TO RETURN THE KEY?
// WOULD THAT IMPLY I NEED TO EXPLICITLY ASSIGN A VALUE TO FIELD key?
return this.key;
// THE ALTERNATIVE WOULD BE TO CREATE A KEY
AND RETURN IT RIGHT? (THEN I CAN EXCLUDE FIELD key?)
// return Key.create(AppUser.class, userId);
}
}
Answering my own question based on further knowledge:
Normally if a parent relationship is desired, one Key is fine. I can't see why another Key field would be required.
I don't think there's 1 right way to assign a value to the #Parent Key. Using this seems to work:
this.parent = Key.create(instanceOfParent);
All classes do not REQUIRE a key field. Use when needed.
There's no one right way to return a Key, both examples could work.
i have a model which has basically just one string variable...i want to write a function to query all the elements in the datastore...how do i do it? also, once i get the result, i want to display the fetched strings in a listview..how do i go abt this???
My class definition is as follows :
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
#PersistenceCapable(identityType = IdentityType.APPLICATION)
public class TrialDB {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Long key;
#Persistent
private String message;
//Accessor Methods etc follow
}
Perhaps you just read Googles docs
http://code.google.com/appengine/docs/java/datastore/jdo/queries.html