How do you query for a list of objects stored using GAE, where a Set field contains a specified string? ie Imagine this imaginary example:
#PersistenceCapable
class Photos {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
String name = "";
Set<String> tag = new Hashset<String>();
}
Assuming there are 40,000 photos in the "database", How do I Query all photos where tag='2009'
Or another example from google's documentation, if you have the following class:
#PersistenceCapable
public class Person {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
#Persistent
private Set<Key> favoriteFoods;
// ...
}
How do you fetch a list of all Person objects where they have a specific favourite food Key?
How would you do that in Java ?
collField.contains(:stringParam)
Try something like this, which is basically taken from the google documentation:
Query query = pm.newQuery("select from com.example.Note where tag == tagname order by created");
query.declareParameters("String tagname");
return (List<Note>) query.execute(tag);
As per the comment below, this also seems to work:
Query query = pm.newQuery("select from com.example.Note where tags.contains(tagname) order by created");
query.declareParameters("String tagname");
return (List<Note>) query.execute(tag);
Related
I got next database structure with OneToOne relation:
[company]
company_id (PK)
company_name
[company_configuration]
company_configuration_id (Autoincrement, PK)
company_id (UNIQUE KEY,FK)
company_configuration_v
I have been using ORMlite and I have next classes for this two tables:
#DatabaseTable(tableName = "company")
public class Company {
public static final String ID_COMPANY = "company_id";
public static final String COMPANY_NAME = "company_name";
#DatabaseField(generatedId = true, columnName = ID_COMPANY)
private int idCompany;
#DatabaseField(columnName = COMPANY_NAME)
private String companyName;
#DatabaseTable(tableName = "company_configuration")
public class CompanyConfiguration {
public static final String COMPANY_CONFIGURATION_ID = "company_configuration_id";
public static final String COMPANY_ID = "company_id";
public static final String COMPANY_CONFIGURATION_V = "company_configuration_v";
#DatabaseField(generatedId = true, columnName = COMPANY_CONFIGURATION_ID)
private int idCompanyConfiguration;
#DatabaseField(foreign = true,foreignAutoRefresh = true, columnName = COMPANY_ID)
private Company companyId;
#DatabaseField(columnName = COMPANY_CONFIGURATION_V)
private String companyConfigurationV;
Here is OneToOne relation because I want to divide a table with many columns.
As you can see in the example above, there is not relation from Company class to CompanyConfiguration class.
I know that I can add this snippet of code(examle below) into Company class, but I don't need a #ForeignCollectionField becaues the collection will contain only one CompanyConfiguration object:
#ForeignCollectionField()
private ForeignCollection<CompanyConfiguration> companyConfigurations;
I need to add something like this (examle below) into Company class and will get the reference from Company class to CompanyConfiguration class:
#OneToOne(targetEntity = CompanyDbConfig.class)
#JoinTable(name = "company_configuration")
#JoinColumn(name = "id_company")
CompanyConfiguration companyConfiguration;
Shortly, I want to get Company object using ORMlite. See the example below. After fetching company from the database, I want to have and CompanyConfiguration object within company object.
Company company = daoCompany.queryForId(id); //daoCompany is an instance of ORMlite Dao class
Is it possible and how to do that using ORMlite?
I posted an OrmLite question myself so I looked through the unanswered questions to see if there was anything I could answer. Even though this is an old topic, I wanted to take a stab at it in case it could help someone.
I've read your post a few times and I think you're asking how to load the information from two tables into one model. You're separating a rather large table into two in the database but you want it to come back as one model. If that is correct, here's my take on the code. This assumes you want to use objects to build the query instead of passing in a query string.
public class CompanyResult
{
public long CompanyId { get; set; }
public long ConfigurationId { get; set; }
public string Name { get; set; }
public string ConfigurationV { get; set; }
}
var query = _db.From<Company>
.Join<CompanyConfiguration>((c, cc) => c.idCompany == cc.idCompany)
.Where(c => c.idCompany == companyId)
.Select<CompanyConfiguration>((c, cc) = new {
CompanyId = c.idCompany,
ConfigurationId = cc.idCompanyConfiguration,
Name = c.companyName,
ConfigurationV - cc.companyConfigurationV
});
var results = _db.Single<CompanyResult>(query);
You'd keep your existing models so they could be used as DTOs. You'd just be using the new model model above to pass back the exact properties you want.
*I wrote this in Notepad++, forgive any typos.
Is there a way to control the fetch size used for owned relationship ?
Example :
#PersistenceCapable
public class Employee {
/** The contact info sets. */
#Persistent(defaultFetchGroup = "true")
#Element(dependent = "true")
private Collection<ContactInfo> contactInfoSets;
/** The key. */
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
public Collection<ContactInfo> getContactInfo() {
return contactInfoSets;
}
}
#PersistenceCapable
public class ContactInfo {
/** The key. */
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
}
In the example above, if I do :
Employee e = pm.getObjectById(Employee.class, "1");
e.getContactInfoSets();
It will fetch every owned contact in group of 20. How to tell jdo to fetch all contacts in a single query ?
PS : I tried to set pm.getFetchPlan().setFetchSize(FetchPlan.FETCH_SIZE_GREEDY); without success.
FetchPlan.setFetchSize is obviously for use by queries and nothing else (as per the spec).
Use of v2 of the GAE JDO plugin ought to load all relation objects without any additional call to the DB (since the ids of the related objects are stored in the owning object). The log tells you what datastore calls are made
Using the peristance manager, how can I retrieve a child object knowing a child property and the parent key?
The Parent is defined like this:
public class User {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key id;
#Persistent(mappedBy = "user")
#Element(dependent = "true")
private List<Section> sections;
...
And the child is defined like this:
public class Section {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Long id;
#Persistent
private User user;
#Persistent
private String title;
...
Knowing the 'User' id and the 'Section' title, how can I retrieve the section?. I was trying to build a query to retrieve the section using something like this: 'where title == xxx AND user.id ¿? == xxx' but I'm not sure how to specify the user id. Is there any way to do it using queries or methods from the persistance manager?
Thanks.
I finally made it with this method:
public static Section getSectionByTitle(String title, Key user_key){
PersistenceManager pm = PMF.get().getPersistenceManager();
Query query = pm.newQuery("select from "+Section.class.getName()+" WHERE title == s && user == keyParam");
query.declareParameters("String s, String k");
query.setUnique(true);
Section section = (Section) query.execute(title, user_key.getId());
return section;
}
You can call this method on the query object:
q.setAncestor(ancestorKey);
Read this page for more information (Ancestor Queries).
I remember seeing something like 'where ANCESTOR = ' syntax but I cannot find any reference for it now.
I have such entity:
#Entity
public class Album {
private Integer id;
private Integer ownerId;
private String name;
private String description;
private Date created;
#OneToMany #JoinColumn(name = "albumId")
private Set<AlbumUser> users = new HashSet<AlbumUser>();
#OneToMany #JoinColumn(name = "albumId")
private Set<Picture> pictures = new HashSet<Picture>();
}
and another one:
#Entity
public class Picture {
private Integer id;
private Integer creatorId;
private Integer albumId;
private Date created;
private String title;
private String description;
#ManyToOne #JoinColumn(name = "eventId")
private Event event;
}
Using Criteria API I want to get unique AlbumDs with filtered set of Picturs. I try something like this:
public Album read(Integer albumId, Set<Integer> picFilter) {
Criteria crit = getCurrentSession().createCriteria(Album.class, "album");
crit.add(Restrictions.idEq(albumId));
if (picFilter != null && !picFilter.isEmpty()) {
crit = crit.createAlias("album.pictures", "picture");
crit.add(Restrictions.in("picture.event.id", picFilter));
crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
}
Album resultDs = (Album) crit.uniqueResult();
return resultDs;
}
And here I get Album with all pictures associated. They're not filtered at all.
When I try to execute query printed by a logger, I get only four rows wich is the number of pictures with given eventId, but in the Album I get all pictures.
I also tried other ResultTransformers, but eventualy got many result (4) not distinct one.
What do I miss or do wrong?
You can not filter the content of Collections associated with an entity by including Restrictions on the Collection in the query. The query will only fetch the Albums. The content of the Collection can be fetched later, when the Collection is accessed. All you do is filter the Albums to retrieve only those Albums that contain the Pictures with the event ids.
If the Collection would only contain the Pictures that match your Criteria and you would get a partial Collection it would cause problems on updates, because Hibernate then think the filtered items have been removed and would update the database to reflect that change, actually removing the items from the Collection.
If you want to receive only some items from a Collection you can use the Session.createFilter() method. The only problem is, that it only supports HQL queries currently.
I recall this being an issue for something I did recently. Have you tried this:
if (picFilter != null && !picFilter.isEmpty()) {
Criteria subCriteria = crit.createCriteria("album.pictures"); // Or just 'pictures?'
Disjunction or = Restrictions.disjunction();
for (Integer id : picFilter)
or.add(Restrictions.idEq(id));
subCriteria.add(or);
crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
}
try this:
Criteria crit = getCurrentSession().createCriteria(Album.class, "album");
crit.add(Restrictions.idEq(albumId));
if (picFilter != null && !picFilter.isEmpty()) {
crit.createAlias("album.pictures", "picture");
crit.createAlias("picture.event", "event");
crit.add(Restrictions.in("event.id", picFilter));
crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
}
If you use alias with left_join, it will return just sub object which satisfy related condition. Otherwise it returns main object which satisfy conditions but with all of sub object set.
crit = crit.createAlias("album.pictures", "picture", CriteriaSpecification.LEFT_JOIN);
This method is deprrecated in some hibernate version, if so you can use below solution for it too:
criteria with filtered complex set
I've omitted some code(package declarations, imports, other fields)
for shortness.
I have here simple One-to-Many relation.
It worked fine till this moment.
#PersistenceCapable(identityType = IdentityType.APPLICATION,
detachable="true")
class Restaurant implements Serializable {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
Key id
#Persistent(mappedBy = "restaurant")
List<RestaurantAddress> addresses = new ArrayList<RestaurantAddress>()
}
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#PersistenceCapable(identityType = IdentityType.APPLICATION,
detachable="true")
class RestaurantAddress implements Serializable {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
Key id
#Persistent
Restaurant restaurant
}
Now i need to get(select) all the Restaurants from DB:
def getRestaurantsToExport(final String dst, final int count) {
String field = restaurantExportFields[dst]
return transactionExecute() { PersistenceManager pm ->
Query q = pm.newQuery(Restaurant.class)
q.filter = "$field == null"
q.setRange(0, count)
return q.execute()
}
}
But there are on problem - query gives me 12 restaurants(as in DB) but
every Restaurant has 0 Address but in Datastore every Restaurant has
minimum 2 addresses.
Have anyone the same problem or knows the solution ?
are you sure the Addresses are not lazy loaded? Just a guess... is there some way to force an "eager" loading of the objects
If someone will have the same problem:
Replace
#Persistent(mappedBy = "restaurant")
List<RestaurantAddress> addresses = new
ArrayList<RestaurantAddress>
with
#Persistent(mappedBy = "restaurant",defaultFetchGroup = "true")
List<RestaurantAddress> addresses = new
ArrayList<RestaurantAddress>
Another method is that you have to "touch" addresses property for
every Restaurant in the retrieved list before closing
PersistentManager. After PersistenManager being closed you cannot
retrieve anything from datastore and Restaurant keeps null.
Solution found with help of google-appengine-java users.