Open cmelchior opened 9 years ago
+1
We've tried composition, but introduced way more problems. Now, instead of developing, we're lots of time hacking the models to fit our bussiness rules. Mangle it with retrofit, deserializers, and all hell broke loose!
This is super painful, I cannot forgive myself for making a huge assumption that Realm supports inheritance. I have a project with a fast-approaching deadline and I had ripped out the good old SQLite/ContentProvider combo and implemented Realm for faster performance and now I hit the wall with Inheritance and composition is not an option for me. I will keep tuned in for this feature.
Overall, I am very happy with all that Realm has offered and I wish the team luck with finding a solution for this.
I'm trying to use Realm and I just ran into this limitation. Is there a timeline for support objects that already have their own inheritance? Composition is not an option for us right now. Is there a timeline for this yet?
+1 - I vote for it. More then a year has passed. BTW it's a middle of 2016!
I had just started migrating from ActiveAndroid to realm and realised that subclassing is still not supported. I think I will have to go back to looking for another ORM.
I also switched back to SQLite for now as I need to work with database from Service and Activity code. I found it hard to use realm in such 'multi-threaded' environment.
I can recommend DbFlow, which supports polymorphism
@bryant1410 Had a quick look at DbFlow. I did not like the code it auto-generates. This is totally a personal preference though. why you think DbFlow is better than something like ActiveAndroid?
Do you mean that you don't like its API? Or the code itself? If you don't like the auto-generated code, this is not a problem as you don't have to read it very often (if at all).
In my opinion the game-changing factor here is the performance. ActiveAndroid relies heavily on reflection, while DBFlow uses annotation processing in order to generate classes and to avoid using reflection as little as possible. Reflection is usually slow in Java, and not using it has a big impact. You can take a look to DBFlow's company benchmark about this.
+1 - If you could find a solution for the inheritance to work, that would be awesome! :)
I have used Realm for quite a while but lack of support of this fundamental OOP characteristic is quite disappointing, a year and a half is quite a long time to have built the required support.
Just ran into this problem. It would be very great if this feature gets prioritized. Gonna have to abandon Realm for now and use other ones. Updates from devs would definitely be appreciated! <O
This issue means I can't attach any JSONAPI deserializers like moshi-jsonapi in Android (which requires that you extend your class with Resource
, which means you can't extend RealmObject
or vice versa. Anybody have a temporary workaround for something like this?
@lordplagus02 See https://realm.io/docs/java/latest/#realmmodel-interface
I think you've just saved my day, what with deadlines fast approaching and solutions undiscovered... you know how it is
@beeender It appears that it still doesn't actually help, you still can't extend or implement anything that isn't Realm related...
@lordplagus02 Sorry I missed that part "moshi-jsonapi in Android (which requires that you extend your class with Resource" ... I think for now you need to find some other ways if you want to use moshi-jsonapi and Realm together, maybe create some delegate class? Not sure if there is an easy way to do it.
@beeender easiest way was to revert to moshi-jsonapi v1.x because it doesn't require that you extend Resource
. I think due to the current limitations of Realm, we're still awhile away from a full jsonapi/realm/syncadapter implementation.
Looking at it, a possibility is forking the project and rewriting it to use interface instead of hard-coding their abstract class
+1
Hello,
I'm trying to reshape my code and models to workaround this issue through composition.
enum ChildType {
CAT, DOG
}
class Animal extends RealmObject implements CatInterface, DogInterface {
@PrimaryKey
@Required
private String id;
@Ignore
private ChildType type;
private String typeDescription;
private ChildMarker child;
public Animal() {
}
public Animal(ChildMarker childMarker) {
if (childMarker instanceof Cat) {
type = ChildType.CAT;
} else if (childMarker instanceof Dog) {
type = ChildType.DOG;
}
}
public ChildType getType() {
if (type == null) {
type = ChildType.valueOf(typeDescription);
}
return type;
}
public void setType(ChildType type) {
this.type = type;
this.typeDescription = type.name();
}
@Override
public Object getCatAttribute() {
if (type != ChildType.CAT) {
return null;
}
return ((Cat) child).getCatAttribute();
}
@Override
public void setCatAttribute(Object catAttribute) {
if (type != ChildType.CAT) {
return;
}
((Cat) child).setCatAttribute(catAttribute);
}
}
interface ChildMarker {
}
interface CatInterface extends ChildMarker {
Object getCatAttribute();
void setCatAttribute(Object catAttribute);
}
class Cat extends RealmObject implements CatInterface {
private Object catAttribute;
@Override
public Object getCatAttribute() {
return catAttribute;
}
@Override
public void setCatAttribute(Object catAttribute) {
this.catAttribute = catAttribute;
}
}
interface DogInterface extends ChildMarker {
}
class Dog extends RealmObject implements DogInterface {
}
But my ChildMarker
is not supported, Does it mean I have to have one attribute of each child type in my Animal
class ? I could also do my composition the other way around, with children containig their mother. But I'd like only one table, I don't know in advance if I'm looking for a dog or a cat and since reverse lookup is in development (#607) I'll have to wait for it.
It would be great if we could have a working code alternative in this topic
enum ChildType {
CAT, DOG
}
class Animal extends RealmObject implements CatInterface, DogInterface {
// animal attributes
@PrimaryKey
@Required
private String id;
@Required
@Index
private String type;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public void setChildType(ChildType childType) {
setType(childType.name());
}
public ChildType getChildType() {
return ChildType.valueOf(this.type);
}
public Animal() {
}
// cat attributes
private String catSomething;
// getter, setter
// dog attributes
private String dogSomething;
// getter, setter
}
interface AnimalInterface {
//animal's fields' getters/setters
}
interface CatInterface extends AnimalInterface {
String getCatSomething();
void setCatSomething(String catSomething);
}
interface DogInterface extends AnimalInterface {
String getDogSomething();
void setDogSomething(String dogSomething);
}
Then
RealmResults<CatInterface> cats =
(RealmResults<CatInterface>)((RealmResults)(realm.where(Animal.class)
.equalTo(AnimalFields.TYPE, ChildType.CAT.name())
.findAll()));
But the interfaces aren't necessary if you can afford to keep it as Animal
.
@Zhuinden Nice ! thanks it looks like what I did but better
Can I bump this? Any update on this feature?
I was just modifying my Realm classes to work with Polymorphism but then I faced this issue ):
I wanted to make General functions to work with my "BaseObject (which extends RealmObject)" so I could use them with any Child classs.
Only interfaces are supported at the moment, base classes other than RealmObject
are not.
I assumed that inheritance is here by default and refactored my code around it without compiling in the process (yes, I am naive but if the support won't be added I am gonna have to have lots of code duplications around primary keys for each model, what the point of using Realm then?) Waiting for an update
@bogomazov
I am gonna have to have lots of code duplications around primary keys for each model
you can always use an interface, and a repository implementation for T extends YourInterface
.
That's what I did, but it causes for quite a bit of un-dry code in your object classes. The interface is just useful for your getters and setters at the end of the day. It desperately needs some polymorphism. On 4 Nov 2016 12:18 am, Gabor Varadi notifications@github.com wrote:
@bogomazov you can always use an interface, and a repository implementation for T extends YourInterface.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.
@lordplagus02 and @bogomazov can you show me an example of the Repository implementation that you got working for you. I am using Repository implementation, maybe I am doing it wrong.
My model class was simple, a LineItem that inherits from a Product like so:
public class LineItem extends Product {
private long id;
private int quantity;
public LineItem(Product product, int quantity) {
super(product);
this.quantity = quantity;
}
}
I have now changed this to this as a work around.
@RealmClass
public class LineItem implements RealmModel {
private long id;
private int quantity;
private long productId;
private Product product;
public LineItem() {
}
public LineItem(Product product, int quantity) {
this.quantity = quantity;
this.productId = product.getId();
this.product = product;
}
}
Here is my repository interface, how can I change my repository implementation to support polymorphism.
public interface Repository{
List<LineItem> getAllLineItemsInATransaction(long transactionId);
long saveLineItem(LineItem lineItem);
void updateLineItem(LineItem lineItem);
LineItem getLineItemById(long id);
void deleteLineItem(long id);
}
I do not see a single place where you're actually sharing fields with Product
.
LineItem is inheriting from Product and then adding properties that are LineItem specific such as quantity, discount, refund, etc. I have not shown those for brevity. The goal is not to duplicate the properties of Product such as name, image, price, etc again in LineItem hence the inheritance.
+1
sigh this is messing with my zen
Wow 2 years
it is a complicated problem, and using common interfaces is a fairly simple workaround
Can someone help with this? http://stackoverflow.com/questions/42259735/composition-over-inheritance-for-realmobjects-with-gson-serialization
I'm totally stuck. This is incredibly frustrating and no one seems to have posted a thorough example of how to work around this issue, and if I can't figure out a workaround, then Realm isn't even an option. I'm astonished they haven't addressed inheritance in two years; I get that development takes time, but inheritance is one of the basic principles of OOP. How can anyone use this if their app has even a modicum of complexity?
You should map your JSON responses into a Realm schema. Don't just directly map GSON's classes into Realm, it's generally a bad idea to assume that your API calls and your database will 1-to-1 match each other directly.
I've made apps that had different types of data and the like, you just need to copy the properties and share a common interface. Frustrating in a sense, inheriting fields is simpler ; but that's just how it is.
Why don't you state clearly in RealmModel interface that class implementing it cannot extend any class? Documentation in current form leads to opposite conclusion.
I really do think the fact that you can't inherit from a class that only has @Ignore
'd fields or no fields at all is a bug.
@Zhuinden But if an object only has @Ignore
fields or no fields, what is the point of being a RealmObject
?
@beeender example code
public class BaseObservable implements Observable {
@Ignore
private transient PropertyChangeRegistry mCallbacks;
@Override
public synchronized void addOnPropertyChangedCallback(OnPropertyChangedCallback callback) {
if (mCallbacks == null) {
mCallbacks = new PropertyChangeRegistry();
}
mCallbacks.add(callback);
}
@Override
public synchronized void removeOnPropertyChangedCallback(OnPropertyChangedCallback callback) {
if (mCallbacks != null) {
mCallbacks.remove(callback);
}
}
@Override
public synchronized void notifyChange() {
if (mCallbacks != null) {
mCallbacks.notifyCallbacks(this, 0, null);
}
}
public void notifyPropertyChanged(int fieldId) {
if (mCallbacks != null) {
mCallbacks.notifyCallbacks(this, fieldId, null);
}
}
}
@RealmClass
public class ObservableDog extends BaseObservable implements RealmModel {
@PrimaryKey
private long id;
private String text;
@Bindable
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
if(!isManaged()) {
notifyPropertyChanged(BR.id);
}
}
@Bindable
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
if(!isManaged()) {
notifyPropertyChanged(BR.text);
}
}
}
This code fails on the Realm annotation processor, even though parent is not a RealmObject and it does not have any inherited fields that Realm could "use"
any update on this issue ?
Any update on this issue?
I have models that look like this:
class Chat extends RealmObject {
RealmList<TextMessage> textMessages;
RealmList<ImageMessage> imageMessages;
}
class Message extends RealmObject {
//some common fields
}
class TextMessage extends RealmObject {
Message baseMessage;
}
class ImageMessage extends RealmObject {
Message baseMessage;
}
instead of looking something like this:
class Chat extends RealmObject {
RealmList<Message> messages
}
class Message extends RealmObject {
//some common fields
}
class TextMessage extends Message {}
class ImageMessage extends Message {}
and it's a nightmare to add more message types or even write queries.
I do not see why you have any more realmObjects beyond Message
@Zhuinden Because I have more fields in TextMessage
and ImageMessage
, which I haven't included here for the sake of readability.
@VedavyasBhat I stand by my question. It would have been easier to just include nullable fields and a @Index String type
field.
@Zhuinden: I see what you have in mind, but I have the same issue as @VedavyasBhat: I want to be able to attach Actions
and Observations
to an object, both being an event in time with some shared attributes. But since both have >10 unique attributes I would end up with a large class Event
which I consider hard to maintain.
Also I am afraid that I will loose productivity when using code completion and that it will add a source for errors (accessing fields from the wrong type, ...).
But it is a feasible workaround, factory methods will help constructing the right type.
When I had this, I prefixed the fields with what event type (in my case, post type) the given field belonged to.
A highly request feature is polymorphism. Mostly for use in ListAdapters, but a lot of other scenarios exists.
We need support for the following:
Example