I have been having issues with persisting a generic Collection on Google datastore using Objectify4. E.g.
#Entity
class AnimalInfo
{
#Id
String id;
Collection<Animal> animals;
}
#EntitySubClass
class Cat extends Animal
{
String name;
}
#EntitySubClass
class Dog extends Animal
{
String name;
}
#Entity
class Animal
{
#Id
String id;
}
How can I persist the AnimalInfo class and retrieve it again. I have tried:
objectify.save().entities(animalInfo).now(); but while fetching it back again: objectify.load().type(AnimalInfo.class).id(animalInfo.id).get(); doesnt have the name field corresponding to the extended class Cat or Dog.
This is also probably logical because Animal class doesnt have a field name. But how do I get this to work? A generic interface IAnimal (in place of Animal class) is a better solution design-wise, but that doesnt work with Objectify as it needs concrete types.
Any solution for the above problem??
Thanks in advance.
Shaun
To summarize, it looks like you want a collection of references to polymorphic entities. Do this:
#Entity
class AnimalInfo {
#Id String id;
Collection<Ref<Animal>> animals = new ArrayList<Ref<Animal>>();
}
You need Refs to create the reference to the other entities. You could use Key too, but it will be less convenient. You may also want to look into the #Load annotation.
Related
I am using Objectify for Google Cloud Datastore.
I am looking into Ref<?> and tried to see if I can modify a property from the object with this annotation but it doesn't seem to be saved in my datastore.
Example:
I have these classes, I'll exlude setters and getters.
#Entity
class Car {
#Id Long id;
#Load Ref<Person> driver; // Person is an #Entity
}
class Person {
#Id Long id;
String name;
}
If I do this
Car car = new Car();
car.driver = Ref.create(driverKey);
ofy().save().entity(car).now();
Car fetched = ofy().load().entity(car).now();
fetched.driver.get().setName("Pepito");
ofy().save().entity(car).now();
It won't change the name of the Person in the database.
Is there any way to achieve this?
Thanks.
References are just that - references to separate entities with separate lives. There is no cascading save. If you want to save the driver, do it explicitly.
is it possible to make this validation:
class Man {
#Unique
String name;
}
class Order {
#Valid
List<Man> manCollection;
}
where is unique logic is: every item in collection manCollection is unique.
You could make this snippet ambiguous just by adding a Customer class that contains a List of Orders:
class Man {
#Unique
String name;
}
class Order {
#Valid
List<Man> manCollection;
}
class Customer {
#Valid
List<Order> orderCollection;
}
Then one couldn't possibly know whether the Man objects must be unique within a given Order or within a given Customer (or both).
So I don't think it's possible with this exact syntax, regardless of what the Bean Validation APIs allow.
What you could do is move the annotation to manCollection, e.g. #UniqueMen List<Man> manCollection;, and implement a ConstraintValidator<List<Man>>.
If it's useful to you, you could even make a more generic #UniqueContent annotation, but that would be much more complex. You would need to pass the target type as a parameter (#UniqueContent(target = Man.class)) and write a validator that parses annotations on the target class in its initialize method. Be careful to use some caching mechanism, though, because annotation parsing is quite slow.
To following is something like... pseudo code... To illustrate what I am looking for:
// Setters and Getters ommitted to keep the example short here:
class Address
{
private String street;
private String city;
}
class AddressBookEntry
{
private String name;
private Address address;
}
class MyController
{
public void render(#RenderParam AddressBookEntry entry)
{
...
}
}
As you can see there are two POJOs (Address and AddressBookEntry). Now I would like to pass an AddressBookEntry to my Controller as http request parameter. I imagine that the URL looks like this: /target?entry.name=Random-Guy&entry.address.street=Random-Street&entry.address.city=Random-City.
As far as I understand #RenderParam doesn't work this way. I would have to create a PropertyEditor that takes a single string and construct my target Object from it, which means that I can't have an individual URL-param for each (sub-)property.
#ModelAttribute comes closer, but I could not find any hint if and how nesting of objects might work with this annotation. Additionally this annotation works without the "entry." prefix in my URL above which means that I need to make sure that I don't have multiple ModelAttributes that share a property name, correct? That sounds stressful.
How can I solve this?
It's the situation when you should use #ModelAttribute. It supports nested objects as you want.
If you need multiple #ModelAttributes, you can compose them into special class (for example, it you case that class can contain a field named entry of type AddressBookEntry, so that parameter names will be the same).
I need to bind request parameters to an instance of the following Java class (getters and setters omitted):
public class ShippingHouse {
private String name;
private String description;
private List<ShippingRule> shippingRules = new ArrayList<ShippingRule>();
}
public class ShippingRule {
private ShippingHouse shippingHouse;
private String name
}
Notice that there is a 1:N relationship between ShippingHouse and ShippingRule, but each ShippingRule also has a reference to the ShippingHouse thaat owns it.
If these were Grails command/domain classes, I would bind them with request parameters
name=foo&description=bar&shippingRules[0].name=sr0&shippingRules[1].name=sr1
But it doesn't seem like this will set the reference to the owning ShippingHouse within each ShippingRule. Is there a way I can bind this automatically, or must I write the code myself?
Don,
You will need to write code to do it yourself using BindUsing or some other approach. The binder doesn't (and shouldn't) assume anything about back references from a parent to a child. If these were GORM entities and the relationship was explicit, that is different, but in your case the binder should not assume that shippingHouse property in the ShippingRule class has anything to do with the shippingRules property in the ShippingHouse class.
Also note that lucke84 said that your "private" is implicit. Make sure you understand what that means if you are going to remove them. If you remove them the compiler is going to generate public getter and setter methods for those properties, which may or may not be what you want.
If you want to implement a 1:N relationship between the two classes, you should use the right grails approach. Something like this:
class ShippingHouse {
String name
String description
static hasMany = [shippingRules: ShippingRule]
}
class ShippingRule {
String name
static belongsTo = [shippingHouse: ShippingHouse]
}
Please note that semicolons are useless and the "private" declaration on class fields is implicit.
I Have 21 entities with the same structure.
Same Attribute too.
Every entity contains these Attributes :
AreaType
ID
IsActive
LangID
TXT
ModuleType
ID
IsActive
LangID
TXT
...
What I Need to perform a generic Crud. I already know that I need to create a generic repository. My problem is to perform a kind of generic ViewModel.
How can I create a generic View for the Create Form.
I Dont know what I need to pass in the Inherits of the view to be Generic.
... Inherits="System.Web.Mvc.ViewPage<...Dont know>"
Any Idea ?
A common approach this problem is to use ViewModels. This is where you create specific classes to be used as the models in your strongly typed views. These classes would not be the ones created by EF. The ViewModel classes can have a common base that encapulate your common fields. In your data access layer you would need to move data between your ViewModel classes and your EF classes. Things like AutoMapper (from CodePlex) work really well to reduce, if not eliminate, all of the the tedious "left-hand right-hand" coding.
Not too familiar with MVC, but (assuming it fits in with your hierarchy), I think you could create an abstract class which contains the properties you need, e.g.
public abstract class ViewableObject {
public abstract int ID {get; set;}
public abstract bool IsActive {get; set;}
// etc
}
Then implement that with your normal classes (AreaType and so on), e.g:
public class AreaType: ViewableObject{
public override int ID { get; set; }
public override bool IsActive{ get; set; }
}
and make the view use the abstract class.
... Inherits="System.Web.Mvc.ViewPage<ViewableObject>"
One idea is to simply change your underlying tables. Combine AreaType and ModuleType into a single "WhateverType" table that contains a field identifying exactly what type it is. Then when you codegen your classes you'll have exactly one class to deal with.
However, there are other concerns and you should only do this if it makes sense in your application.