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.
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.
I'm running into the issue of the child not having the reference to its parent. Supposedly I've got the setup of a bidirectional relationship where I can get children from the parent and get the parent from the child; however my childrens' parents are always coming back null.
I've got a parent of,
#PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Company {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
#Persistent(mappedBy = "company")
private List<Employee> employees = new ArrayList<Employee>();
}
With a child of,
#PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Employee {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
#Persistent
private Company company;
#Persistent
private String username;
}
I'm persisting the object by,
Company newCompany = new Company();
Employee newEmployee = new Employee();
newEmployee.setUsername("ryan");
newCompany.getEmployees().add(newEmployee);
pm.makePersistent(newCompany);
I'm accessing the object like so,
Query query = pm.newQuery(Employee.class,"username == s");
query.declareParameters("String s");
List<Employee> employees = (List<Employee>)query.execute(username);
pm.close();
if (employees.size() > 0)
{
Employee employee = employeeList.get(0);
...
}
I'm then seeing "company" as null when debugging while the rest of the employee's fields are populated. Any thoughts on what I'm missing?
Fetching of the parent depends on where you check it, according to the object state. If your PM has been closed by that point then it will not have fetched the parent field. Touching the parent field before closing the PM (and having retainValues set to true, or detaching at close of the PM) will result in the parent field being set.
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
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);
I am trying to load the full object graph for User, which contains a
collection of decks, which then contains a collection of cards, as
such:
User:
#PersistenceCapable(detachable = "true")
#Inheritance(strategy = InheritanceStrategy.SUBCLASS_TABLE)
#FetchGroup(name = "decks", members = { #Persistent(name =
"_Decks") })
public abstract class User {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
protected Key _ID;
#Persistent
protected String _UniqueIdentifier;
#Persistent(mappedBy = "_Owner")
#Element(dependent = "true")
protected Set<Deck> _Decks;
protected User()
{
}
}
Each Deck has a collection of Cards, as such:
#PersistenceCapable(detachable = "true")
#FetchGroup(name = "cards", members = { #Persistent(name =
"_Cards") })
public class Deck {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key _ID;
#Persistent
String _Name;
#Persistent(mappedBy = "_Parent")
#Element(dependent = "true")
private Set<Card> _Cards = new HashSet<Card>();
#Persistent
private Set<String> _Tags = new HashSet<String>();
#Persistent
private User _Owner;
}
And finally, each card:
#PersistenceCapable
public class Card {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key _ID;
#Persistent
private Text _Question;
#Persistent
private Text _Answer;
#Persistent
private Deck _Parent;
}
I am trying to retrieve and then detach the entire object graph. I
can see in the debugger that it loads fine, but then when I get to
detaching, I can't make anything beyond the User object load. (No
Decks, no Cards). At first I tried without a transaction to simply
"touch" all the fields on the attached object before detaching, but
that didn't help. Then I tried adding everything to the default fetch
group, but that just generated warnings about GAE not supporting
joins. I tried setting the fetch plan's max fetch depth to -1, but
that didn't do it. Finally, I tried using FetchGroups as you can see
above, and then retrieving with the following code:
PersistenceManager pm = _pmf.getPersistenceManager();
pm.setDetachAllOnCommit(true);
pm.getFetchPlan().setGroup("decks");
pm.getFetchPlan().setGroup("cards");
Transaction tx = pm.currentTransaction();
Query query = null;
try {
tx.begin();
query = pm.newQuery(GoogleAccountsUser.class); //Subclass of User
query.setFilter("_UniqueIdentifier == TheUser");
query.declareParameters("String TheUser");
List<User> results = (List<User>)query.execute(ID); //ID = Supplied
parameter
//TODO: Test for more than one result and throw
if(results.size() == 0)
{
tx.commit();
return null;
}
else
{
User usr = (User)results.get(0);
//usr = pm.detachCopy(usr);
tx.commit();
return usr;
}
} finally {
query.closeAll();
if (tx.isActive())
{
tx.rollback();
}
pm.close();
}
This also doesn't work, and I'm running out of ideas...
I'm sure reading of the log (Debug level) would tell you way more, since it certainly tells you when it is detaching things. Perhaps GAE/J is not respecting lazy loading at detach ? DataNucleus itself works fine, with all other datastores.
Why call FetchPlan.setGroup() when that overwrites all existing groups ? addGroup() makes more sense to me.