Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compound primary keys #1129

Open
cmelchior opened this issue May 17, 2015 · 51 comments
Open

Compound primary keys #1129

cmelchior opened this issue May 17, 2015 · 51 comments

Comments

@cmelchior
Copy link
Contributor

cmelchior commented May 17, 2015

Realm should also support composite primary keys. Reusing the @PrimaryKey annotation should be relatively simple.

public class CompositeKeyObj extends RealmObject {

  @PrimaryKey
  private int compositePartOne;

  @PrimaryKey
  private int compositePartTwo;
}

Primary keys are currently implemented in the binding. This should be implemented at the core level: realm/realm-core#831

@cmelchior cmelchior added T-Enhancement Blocked This issue is blocked by another issue backlog labels May 17, 2015
@senorcris
Copy link

This feature would be great is it still on the roadmap? If not are there any work arounds that could be used in the meantime to get composite keys?

@shawnwall
Copy link

+1

@ghost
Copy link

ghost commented Sep 15, 2015

How can I check status of this task?

@carmas123
Copy link

+1

@hunain-liaquat
Copy link

+1

@saket
Copy link

saket commented Jan 23, 2016

This would solve a problem I'm currently facing. Would be a great feature to have!

@dongseok0
Copy link

It's been 6 months. What's status?

@yuwu
Copy link

yuwu commented Feb 3, 2016

+1

7 similar comments
@willf80
Copy link

willf80 commented Mar 5, 2016

+1

@ohcrfpv
Copy link

ohcrfpv commented Mar 13, 2016

+1

@yuwu
Copy link

yuwu commented Mar 15, 2016

+1

@pratamawijaya
Copy link

+1

@mksengun
Copy link

+1

@marchy
Copy link

marchy commented Apr 5, 2016

+1

@mmartikainen
Copy link

+1

@marchy
Copy link

marchy commented Apr 6, 2016

One workaround we've used as a way of getting around this limitation is to create an 'id' property which simply concatenates the different fields that you want to use in your composite key. This way you get the uniqueness integrity checks but you can still program against the proper abstractions (ie: foreign keys/objects that make up your composite key - especially useful for "link table" objects between your various entities.

@wuwu2000
Copy link

+1

2 similar comments
@razelsoco
Copy link

+1

@mgdiez
Copy link

mgdiez commented Jul 25, 2016

+1

@halfred888
Copy link

A workaround what I have been using is to create the unique id of combining two id's before assigning it to realm object eg.

class Pet : Object {
dynamic var combinedPrimary : String = ""
override class func primaryKey() -> String? {
      return "combinedPrimary" 
   }
}
let combinedKey = "\(person.id)\(pet.id)"
pet.combinedPrimary = combinedKey 

@marchy
Copy link

marchy commented Aug 5, 2016

@RealPunk yup I think that's the recommended workaround. It's probably why the team hasn't been prioritizing this very much - along with the fact that Realm doesn't really expose foreign keys in any way (I'm no expert here, just my experience with it). So unlike traditional ORMs where you want to keep foreign keys around on objects to link to them in Realm you link to the object instance directly and the backing ID/structure is hidden from the programming model.

For readability/sanity purposes I'd recommend throwing an extra ":" separator in there so you can re-infer the original IDs if needed:

ie: "(person.id):(pet.id)"

@StefanoGR
Copy link

+1

@Dragas
Copy link

Dragas commented Jan 16, 2017

Or you know, instead of writing +1 just click that "Subscribe" button.

@Zhuinden
Copy link
Contributor

@Dragas agreed. Also, just +1 doesn't provide a use-case or anything. For me, concatenating values into a single indexed String field has always solved "compound primary key" problems.

@HsiangLeekwok
Copy link

HsiangLeekwok commented Jan 24, 2017

+1

// realm-java, this is what I used:
public class Foo extends RealmObject {
    @PrimaryKey
    private String primaryKey;
    private long id;
    private int type;
    private String name;

    // getter and setter

    // local defined primary key
    public void compoundPrimaryKey() {
        if(!isManaged()) {
            // only unmanaged objects needs compound key
            this.primaryKey = String.format("[I:%d][T:%d]", this.id, this.type);
        }
    }
}
// using
Foo foo = gson.fromJson(json, Foo.class);
foo.compoundPrimaryKey();
realm.insertOrUpdate(foo);
// or
List<Foo> foos = gson.fromJson(json, new TypeToken<List<Foo>>(){}.getType());
for (Foo foo: foos) {
    foo.compoundPrimaryKey();
}
realm.insertOrUpdate(foos);

@marafat
Copy link

marafat commented Apr 5, 2017

I am currently using something similar to the example by @HsiangLeekwok. But there are a couple of problems with that:

  • Since this primaryKey string is part of the realm object, it needs to have a public mutator. There is no clean way to convey to the rest of your team to avoid using this mutator and rather call compoundPrimaryKey(). I am currently annotating it as @Deprecated with a link ref to my version of compoundPrimaryKey().
  • You also have to make it clear that calling compoundPrimaryKey must not only be done on an unmanaged obj, it should also be on an obj that has both id & type none null. If both were to be marked as @PrimaryKey, it comes naturally knowing that you have to set primary keys before inserting objs into realm.

@Zhuinden
Copy link
Contributor

Zhuinden commented Apr 5, 2017

Since this primaryKey string is part of the realm object, it needs to have a public mutator.

Are you sure? I don't think it needs to have a public mutator since 0.88.0.

But I could be wrong.

@marafat
Copy link

marafat commented Apr 6, 2017

@Zhuinden I think you are right. I just tried with a simple test app where I didn't even generate a setter for the "compound primary key string". And was able to insert a new instance to the realm. I verified the obj by using this compound key to query for the obj and print it to logcat, and I also verified it with the realm browser.

In my defense, the docs mentions "Standard setters and getters", and they are exposed as public in the example.

@renattomachado
Copy link

+1

2 similar comments
@devpedrofranco
Copy link

+1

@d3bt3ch
Copy link

d3bt3ch commented Dec 23, 2017

+1

@behelit
Copy link

behelit commented Jan 8, 2018

Any clean code to do this? The suggestions so far seem horrible or aren't even java

@Zhuinden
Copy link
Contributor

Zhuinden commented Jan 8, 2018

@behelit the current solution is still to keep your own "compound" String key that is constructed by concatenating whatever fields you wanted it to be based on

Once you create a managed object with a given primary key, you can't mutate its primary key though, so keep that in mind

@hmedat
Copy link

hmedat commented Feb 15, 2018

+18

@CsabaMiomni
Copy link

+1 million

@MartinaMuscarella
Copy link

+1

3 similar comments
@guisteps
Copy link

+1

@svazquezcds
Copy link

+1

@GBenoitG
Copy link

+1

@lzbrady
Copy link

lzbrady commented Dec 6, 2018

I am getting a list of object that I write to the realm that I would like to generate a compound key for. Do I have to loop over the list of incoming data and generate the compound key for each object? Or is there some method I can override or something to generate the primary key as it is being written to the realm?

@Zhuinden
Copy link
Contributor

Zhuinden commented Dec 6, 2018

Do I have to loop over the list of incoming data and generate the compound key for each object?

yes

Or is there some method I can override or something to generate the primary key as it is being written to the realm?

no

(exception being that you set the compound primary key in a not-no-arg-constructor that Realm doesn't use but you do)

@A-BEECHEY
Copy link

When you want to persist a json array directly into a realm database you CANNOT ".. just concatenate the values together into a String."

On the whole REALM is a brilliant mobile database, seems a pity that there a few "potholes" that have existed for some time which seem (on the face of it) to be obviously in need of fixing.

The other is an AUTO incrementing primary key.

Sure you can work round these, but is that really an acceptable solution in the 21st Century?

If Realm wants to be take seriously can then take the time to iron out these wrinkles?

@Zhuinden
Copy link
Contributor

Zhuinden commented Dec 10, 2018

When you want to persist a json array directly into a realm database you CANNOT ".. just concatenate the values together into a String."

I mean it worked for me, I just had to use a stream JSON parser to do it (considering I was saving 15000 items at a time).

The other is an AUTO incrementing primary key.

Auto-increment PKs aren't that useful in Realm because you don't need a PK/FK to do "joins" because the concept of "Joins" and "foreign keys" doesn't exist in Realm.

They'd only be useful if you detach and then try to re-attach objects often, and the object is created locally.

It's better if a backend manages the IDs and you just download them and insert as is, in which case you don't need to manage auto-increment on your client side.

KerDW added a commit to KerDW/AndroidProject that referenced this issue Dec 6, 2019
@RealmBot RealmBot removed the Blocked This issue is blocked by another issue label Sep 24, 2020
@gkalmpenis
Copy link

I am also in need of this, will use the workaround with string concatenation for now and just commenting in case someone has the capacity to implement it 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests