Realm: Auto-Incrementing Primary Key












4















I'm trying out Realm by implementing a simple financial book-keeping tool. I'm working with a schema that looks something like the following (inheriting from a sql based project)



Example Schema



Initially I setup classes for all of these tables with a PrimaryKey of type long. Then I learned that, at least as of 2015, realm doesn't support auto-increment. In my own testing it appears to be true, as I get an exception saying 0 is a duplicate primary key.



Looking at the examples on the getting started guide I tried to re-evaluate if I actually needed specific Id fields. For the most part it doesn't seem I particularly do aside from potential speed benefits of using a primary key in the database. But it seems reasonable to me to expect that Realm does this under the hood when I setup relations anyways. There was one exception though.



// TransactionLink.cs
using Realms;

namespace Finance.Models {
public class TransactionLink : RealmObject {
public Transaction Lhs { get; set; }
public Transaction Rhs { get; set; }
}
}

// Transaction.cs
using Realms;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Finance.Models {
public class Transaction : RealmObject {
[PrimaryKey]
public long Id { get; set; }

// ...

[Ignored]
public IQueryable<Transaction> LinkedTransactions {
get {
var lhs = Realm.All<TransactionLink>().Where(tl => tl.Lhs.Id == Id).Select(tl => tl.Rhs);
var rhs = Realm.All<TransactionLink>().Where(tl => tl.Rhs.Id == Id).Select(tl => tl.Lhs);
return lhs.Union(rhs);
}
}
}
}


At first I considered perhaps having Transaction have a field IList<Transaction> but I didn't like the removed benefit of having one entry that adds it to both of them. Having to maintain separate copies of the data wasn't appealing to me. I considered instead of comparing the Id using the Equals function as I noticed RealmObject overloads it (something like tl => tl.Rhs.Equals(this)), but I wasn't sure how it would handle in queries (maybe I should try that after posting this question...but I'm a little ways from being able to test that)



Well, at this point (I could be wrong) it seems it was best for me to implement something auto-incrementing. So following off the example in the afore-mentioned stack overflow post I came up with something.



// IPrimaryKeyId.cs
namespace Finance.Context {
public interface IPrimaryKeyId {
long Id { get; set; }
}
}

// Database.cs
using Finance.Models;
using Realms;
using System.Linq;
using System.Windows;
using static Finance.Context.Handle;

namespace Finance.Context {
public class Database {
//-------------------------------------------------------------------------------------------------------------+
// Non-Static Interface: Provide access to all the tables in the database |
//-------------------------------------------------------------------------------------------------------------+
private Realm Db { get; set; }
public IQueryable<Bank> Banks { get { return Db.All<Bank>(); } }
public IQueryable<Models.Transaction> Transactions { get { return Db.All<Models.Transaction>(); } }
public IQueryable<TransactionLink> TransactionLinks { get { return Db.All<TransactionLink>(); } }
// ...

public void SetupExample() {
AutoIncrement(new Bank { Name = "Cash" });
var first = Banks.First();
MessageBox.Show(first.Id.ToString() + ": " + first.Name);
}

public void AutoIncrement<T>(T obj) where T : RealmObject, IPrimaryKeyId {
AutoIncrement(Db, obj);
}

public static void AutoIncrement<T>(Realm db, T obj) where T : RealmObject, IPrimaryKeyId {
db.Write(() => {
long id = db.All<T>().Max(el => el.Id);
obj.Id = id + 1;
db.Add(obj);
});
}
}
}


The afore-mentioned guide says realm doesn't like inheritance in these classes but it seemed to run ok with this simple interface. The problem is that on the line that calls Max() it throws a NotSupportedException. So now I'm left with a few potential problems to solve, any one of which will get me moving forward.




  1. Alternative to Max() for determining the max Id

  2. Verifying the efficacy of using Equals(this) inside of a Linq query and ditching Ids all together

  3. Another alternative I haven't considered


This is for me getting accustomed to realm, so as much as possible I want to do things "the realm way". Any other comments about how I can fit that style better are welcome.



Responses to @Cristo



The line in question where the exception gets called is long id = db.All<T>().Max(el => el.Id); as you can see in the above code snippet. The exact text is System.NotSupportedException: 'The method 'Max' is not supported'. The stack trace is



[External Code] 
Finance.exe!Finance.Context.Database.AutoIncrement.AnonymousMethod__0() Line 48 C#
[External Code]
Finance.exe!Finance.Context.Database.AutoIncrement<Finance.Context.Handle>(Realms.Realm db, Finance.Context.Handle obj) Line 47 C#
Finance.exe!Finance.Context.Database.Create(string file) Line 74 C#
Finance.exe!Finance.MainWindow.Button_Click(object sender, System.Windows.RoutedEventArgs e) Line 14 C#
[External Code]


Where line 47 corresponds to the db.Write( and 48 corresponds to the line with the call to Max










share|improve this question

























  • github.com/realm/realm-dotnet/issues/new "We monitor the realm tag." - So where are you?....

    – Assimilater
    Jan 10 at 21:15
















4















I'm trying out Realm by implementing a simple financial book-keeping tool. I'm working with a schema that looks something like the following (inheriting from a sql based project)



Example Schema



Initially I setup classes for all of these tables with a PrimaryKey of type long. Then I learned that, at least as of 2015, realm doesn't support auto-increment. In my own testing it appears to be true, as I get an exception saying 0 is a duplicate primary key.



Looking at the examples on the getting started guide I tried to re-evaluate if I actually needed specific Id fields. For the most part it doesn't seem I particularly do aside from potential speed benefits of using a primary key in the database. But it seems reasonable to me to expect that Realm does this under the hood when I setup relations anyways. There was one exception though.



// TransactionLink.cs
using Realms;

namespace Finance.Models {
public class TransactionLink : RealmObject {
public Transaction Lhs { get; set; }
public Transaction Rhs { get; set; }
}
}

// Transaction.cs
using Realms;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Finance.Models {
public class Transaction : RealmObject {
[PrimaryKey]
public long Id { get; set; }

// ...

[Ignored]
public IQueryable<Transaction> LinkedTransactions {
get {
var lhs = Realm.All<TransactionLink>().Where(tl => tl.Lhs.Id == Id).Select(tl => tl.Rhs);
var rhs = Realm.All<TransactionLink>().Where(tl => tl.Rhs.Id == Id).Select(tl => tl.Lhs);
return lhs.Union(rhs);
}
}
}
}


At first I considered perhaps having Transaction have a field IList<Transaction> but I didn't like the removed benefit of having one entry that adds it to both of them. Having to maintain separate copies of the data wasn't appealing to me. I considered instead of comparing the Id using the Equals function as I noticed RealmObject overloads it (something like tl => tl.Rhs.Equals(this)), but I wasn't sure how it would handle in queries (maybe I should try that after posting this question...but I'm a little ways from being able to test that)



Well, at this point (I could be wrong) it seems it was best for me to implement something auto-incrementing. So following off the example in the afore-mentioned stack overflow post I came up with something.



// IPrimaryKeyId.cs
namespace Finance.Context {
public interface IPrimaryKeyId {
long Id { get; set; }
}
}

// Database.cs
using Finance.Models;
using Realms;
using System.Linq;
using System.Windows;
using static Finance.Context.Handle;

namespace Finance.Context {
public class Database {
//-------------------------------------------------------------------------------------------------------------+
// Non-Static Interface: Provide access to all the tables in the database |
//-------------------------------------------------------------------------------------------------------------+
private Realm Db { get; set; }
public IQueryable<Bank> Banks { get { return Db.All<Bank>(); } }
public IQueryable<Models.Transaction> Transactions { get { return Db.All<Models.Transaction>(); } }
public IQueryable<TransactionLink> TransactionLinks { get { return Db.All<TransactionLink>(); } }
// ...

public void SetupExample() {
AutoIncrement(new Bank { Name = "Cash" });
var first = Banks.First();
MessageBox.Show(first.Id.ToString() + ": " + first.Name);
}

public void AutoIncrement<T>(T obj) where T : RealmObject, IPrimaryKeyId {
AutoIncrement(Db, obj);
}

public static void AutoIncrement<T>(Realm db, T obj) where T : RealmObject, IPrimaryKeyId {
db.Write(() => {
long id = db.All<T>().Max(el => el.Id);
obj.Id = id + 1;
db.Add(obj);
});
}
}
}


The afore-mentioned guide says realm doesn't like inheritance in these classes but it seemed to run ok with this simple interface. The problem is that on the line that calls Max() it throws a NotSupportedException. So now I'm left with a few potential problems to solve, any one of which will get me moving forward.




  1. Alternative to Max() for determining the max Id

  2. Verifying the efficacy of using Equals(this) inside of a Linq query and ditching Ids all together

  3. Another alternative I haven't considered


This is for me getting accustomed to realm, so as much as possible I want to do things "the realm way". Any other comments about how I can fit that style better are welcome.



Responses to @Cristo



The line in question where the exception gets called is long id = db.All<T>().Max(el => el.Id); as you can see in the above code snippet. The exact text is System.NotSupportedException: 'The method 'Max' is not supported'. The stack trace is



[External Code] 
Finance.exe!Finance.Context.Database.AutoIncrement.AnonymousMethod__0() Line 48 C#
[External Code]
Finance.exe!Finance.Context.Database.AutoIncrement<Finance.Context.Handle>(Realms.Realm db, Finance.Context.Handle obj) Line 47 C#
Finance.exe!Finance.Context.Database.Create(string file) Line 74 C#
Finance.exe!Finance.MainWindow.Button_Click(object sender, System.Windows.RoutedEventArgs e) Line 14 C#
[External Code]


Where line 47 corresponds to the db.Write( and 48 corresponds to the line with the call to Max










share|improve this question

























  • github.com/realm/realm-dotnet/issues/new "We monitor the realm tag." - So where are you?....

    – Assimilater
    Jan 10 at 21:15














4












4








4








I'm trying out Realm by implementing a simple financial book-keeping tool. I'm working with a schema that looks something like the following (inheriting from a sql based project)



Example Schema



Initially I setup classes for all of these tables with a PrimaryKey of type long. Then I learned that, at least as of 2015, realm doesn't support auto-increment. In my own testing it appears to be true, as I get an exception saying 0 is a duplicate primary key.



Looking at the examples on the getting started guide I tried to re-evaluate if I actually needed specific Id fields. For the most part it doesn't seem I particularly do aside from potential speed benefits of using a primary key in the database. But it seems reasonable to me to expect that Realm does this under the hood when I setup relations anyways. There was one exception though.



// TransactionLink.cs
using Realms;

namespace Finance.Models {
public class TransactionLink : RealmObject {
public Transaction Lhs { get; set; }
public Transaction Rhs { get; set; }
}
}

// Transaction.cs
using Realms;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Finance.Models {
public class Transaction : RealmObject {
[PrimaryKey]
public long Id { get; set; }

// ...

[Ignored]
public IQueryable<Transaction> LinkedTransactions {
get {
var lhs = Realm.All<TransactionLink>().Where(tl => tl.Lhs.Id == Id).Select(tl => tl.Rhs);
var rhs = Realm.All<TransactionLink>().Where(tl => tl.Rhs.Id == Id).Select(tl => tl.Lhs);
return lhs.Union(rhs);
}
}
}
}


At first I considered perhaps having Transaction have a field IList<Transaction> but I didn't like the removed benefit of having one entry that adds it to both of them. Having to maintain separate copies of the data wasn't appealing to me. I considered instead of comparing the Id using the Equals function as I noticed RealmObject overloads it (something like tl => tl.Rhs.Equals(this)), but I wasn't sure how it would handle in queries (maybe I should try that after posting this question...but I'm a little ways from being able to test that)



Well, at this point (I could be wrong) it seems it was best for me to implement something auto-incrementing. So following off the example in the afore-mentioned stack overflow post I came up with something.



// IPrimaryKeyId.cs
namespace Finance.Context {
public interface IPrimaryKeyId {
long Id { get; set; }
}
}

// Database.cs
using Finance.Models;
using Realms;
using System.Linq;
using System.Windows;
using static Finance.Context.Handle;

namespace Finance.Context {
public class Database {
//-------------------------------------------------------------------------------------------------------------+
// Non-Static Interface: Provide access to all the tables in the database |
//-------------------------------------------------------------------------------------------------------------+
private Realm Db { get; set; }
public IQueryable<Bank> Banks { get { return Db.All<Bank>(); } }
public IQueryable<Models.Transaction> Transactions { get { return Db.All<Models.Transaction>(); } }
public IQueryable<TransactionLink> TransactionLinks { get { return Db.All<TransactionLink>(); } }
// ...

public void SetupExample() {
AutoIncrement(new Bank { Name = "Cash" });
var first = Banks.First();
MessageBox.Show(first.Id.ToString() + ": " + first.Name);
}

public void AutoIncrement<T>(T obj) where T : RealmObject, IPrimaryKeyId {
AutoIncrement(Db, obj);
}

public static void AutoIncrement<T>(Realm db, T obj) where T : RealmObject, IPrimaryKeyId {
db.Write(() => {
long id = db.All<T>().Max(el => el.Id);
obj.Id = id + 1;
db.Add(obj);
});
}
}
}


The afore-mentioned guide says realm doesn't like inheritance in these classes but it seemed to run ok with this simple interface. The problem is that on the line that calls Max() it throws a NotSupportedException. So now I'm left with a few potential problems to solve, any one of which will get me moving forward.




  1. Alternative to Max() for determining the max Id

  2. Verifying the efficacy of using Equals(this) inside of a Linq query and ditching Ids all together

  3. Another alternative I haven't considered


This is for me getting accustomed to realm, so as much as possible I want to do things "the realm way". Any other comments about how I can fit that style better are welcome.



Responses to @Cristo



The line in question where the exception gets called is long id = db.All<T>().Max(el => el.Id); as you can see in the above code snippet. The exact text is System.NotSupportedException: 'The method 'Max' is not supported'. The stack trace is



[External Code] 
Finance.exe!Finance.Context.Database.AutoIncrement.AnonymousMethod__0() Line 48 C#
[External Code]
Finance.exe!Finance.Context.Database.AutoIncrement<Finance.Context.Handle>(Realms.Realm db, Finance.Context.Handle obj) Line 47 C#
Finance.exe!Finance.Context.Database.Create(string file) Line 74 C#
Finance.exe!Finance.MainWindow.Button_Click(object sender, System.Windows.RoutedEventArgs e) Line 14 C#
[External Code]


Where line 47 corresponds to the db.Write( and 48 corresponds to the line with the call to Max










share|improve this question
















I'm trying out Realm by implementing a simple financial book-keeping tool. I'm working with a schema that looks something like the following (inheriting from a sql based project)



Example Schema



Initially I setup classes for all of these tables with a PrimaryKey of type long. Then I learned that, at least as of 2015, realm doesn't support auto-increment. In my own testing it appears to be true, as I get an exception saying 0 is a duplicate primary key.



Looking at the examples on the getting started guide I tried to re-evaluate if I actually needed specific Id fields. For the most part it doesn't seem I particularly do aside from potential speed benefits of using a primary key in the database. But it seems reasonable to me to expect that Realm does this under the hood when I setup relations anyways. There was one exception though.



// TransactionLink.cs
using Realms;

namespace Finance.Models {
public class TransactionLink : RealmObject {
public Transaction Lhs { get; set; }
public Transaction Rhs { get; set; }
}
}

// Transaction.cs
using Realms;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Finance.Models {
public class Transaction : RealmObject {
[PrimaryKey]
public long Id { get; set; }

// ...

[Ignored]
public IQueryable<Transaction> LinkedTransactions {
get {
var lhs = Realm.All<TransactionLink>().Where(tl => tl.Lhs.Id == Id).Select(tl => tl.Rhs);
var rhs = Realm.All<TransactionLink>().Where(tl => tl.Rhs.Id == Id).Select(tl => tl.Lhs);
return lhs.Union(rhs);
}
}
}
}


At first I considered perhaps having Transaction have a field IList<Transaction> but I didn't like the removed benefit of having one entry that adds it to both of them. Having to maintain separate copies of the data wasn't appealing to me. I considered instead of comparing the Id using the Equals function as I noticed RealmObject overloads it (something like tl => tl.Rhs.Equals(this)), but I wasn't sure how it would handle in queries (maybe I should try that after posting this question...but I'm a little ways from being able to test that)



Well, at this point (I could be wrong) it seems it was best for me to implement something auto-incrementing. So following off the example in the afore-mentioned stack overflow post I came up with something.



// IPrimaryKeyId.cs
namespace Finance.Context {
public interface IPrimaryKeyId {
long Id { get; set; }
}
}

// Database.cs
using Finance.Models;
using Realms;
using System.Linq;
using System.Windows;
using static Finance.Context.Handle;

namespace Finance.Context {
public class Database {
//-------------------------------------------------------------------------------------------------------------+
// Non-Static Interface: Provide access to all the tables in the database |
//-------------------------------------------------------------------------------------------------------------+
private Realm Db { get; set; }
public IQueryable<Bank> Banks { get { return Db.All<Bank>(); } }
public IQueryable<Models.Transaction> Transactions { get { return Db.All<Models.Transaction>(); } }
public IQueryable<TransactionLink> TransactionLinks { get { return Db.All<TransactionLink>(); } }
// ...

public void SetupExample() {
AutoIncrement(new Bank { Name = "Cash" });
var first = Banks.First();
MessageBox.Show(first.Id.ToString() + ": " + first.Name);
}

public void AutoIncrement<T>(T obj) where T : RealmObject, IPrimaryKeyId {
AutoIncrement(Db, obj);
}

public static void AutoIncrement<T>(Realm db, T obj) where T : RealmObject, IPrimaryKeyId {
db.Write(() => {
long id = db.All<T>().Max(el => el.Id);
obj.Id = id + 1;
db.Add(obj);
});
}
}
}


The afore-mentioned guide says realm doesn't like inheritance in these classes but it seemed to run ok with this simple interface. The problem is that on the line that calls Max() it throws a NotSupportedException. So now I'm left with a few potential problems to solve, any one of which will get me moving forward.




  1. Alternative to Max() for determining the max Id

  2. Verifying the efficacy of using Equals(this) inside of a Linq query and ditching Ids all together

  3. Another alternative I haven't considered


This is for me getting accustomed to realm, so as much as possible I want to do things "the realm way". Any other comments about how I can fit that style better are welcome.



Responses to @Cristo



The line in question where the exception gets called is long id = db.All<T>().Max(el => el.Id); as you can see in the above code snippet. The exact text is System.NotSupportedException: 'The method 'Max' is not supported'. The stack trace is



[External Code] 
Finance.exe!Finance.Context.Database.AutoIncrement.AnonymousMethod__0() Line 48 C#
[External Code]
Finance.exe!Finance.Context.Database.AutoIncrement<Finance.Context.Handle>(Realms.Realm db, Finance.Context.Handle obj) Line 47 C#
Finance.exe!Finance.Context.Database.Create(string file) Line 74 C#
Finance.exe!Finance.MainWindow.Button_Click(object sender, System.Windows.RoutedEventArgs e) Line 14 C#
[External Code]


Where line 47 corresponds to the db.Write( and 48 corresponds to the line with the call to Max







c# .net realm






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Feb 12 at 20:51







Assimilater

















asked Jan 2 at 22:08









AssimilaterAssimilater

6891029




6891029













  • github.com/realm/realm-dotnet/issues/new "We monitor the realm tag." - So where are you?....

    – Assimilater
    Jan 10 at 21:15



















  • github.com/realm/realm-dotnet/issues/new "We monitor the realm tag." - So where are you?....

    – Assimilater
    Jan 10 at 21:15

















github.com/realm/realm-dotnet/issues/new "We monitor the realm tag." - So where are you?....

– Assimilater
Jan 10 at 21:15





github.com/realm/realm-dotnet/issues/new "We monitor the realm tag." - So where are you?....

– Assimilater
Jan 10 at 21:15












2 Answers
2






active

oldest

votes


















1















The problem is that on the line that calls Max() it throws a NotSupportedException




Assuming you have an int|long|... type as the primary key, you can use Last() on a transient query to obtain the last|max id value and manually increment it by one (since the Realm query is lazy loaded, only the last object is instanced to determine the current value of the primary key).



Example:



public class ItemModel : RealmObject
{
public ItemModel() { }

public ItemModel(int ID)
{
this.ID = ID;
}

[PrimaryKey]
public int ID { get; set; }

public static ItemModel Create()
{
ItemModel NewItemModel()
{
var q = Realm.GetInstance(Consts.realmDBName).All<ItemModel>();
return new ItemModel(q.Any() ? q.Last().ID + 1 : 0);
}

if (Realm.GetInstance(Consts.realmDBName).IsInTransaction)
{
return NewItemModel();
}
// Use a pseudo transaction to ensure multi-process safety on obtaining the last record
using (var trans = Realm.GetInstance(Consts.realmDBName).BeginWrite())
{
return NewItemModel();
}
}

}


Usage:



var aRealmObject = instance.Add(ItemModel.Create(), false);





share|improve this answer
























  • The Create function you put forward as an example would have to be copy pasted onto every class that inherits RealmObject, which is the reason I went towards implementing an interface. However the suggestion of Last I was able to bring into my solution and it appears to be working. I do wonder however if I will run into any problems down the road for reasons similar to the exception message I mentioned in comment to Cristo's answer: IPrimaryKeyId is not in the limited set of classes for this Realm. Thoughts?

    – Assimilater
    Feb 12 at 21:02











  • @Assimilater You do not have to copy/paste the static Create method into each model, you could create a Class Factory that automatically sets the primary key (based upon the same logic, just in a generic fashion..., I only expose the RealmObject inheritance as a model-based interface, so it really does not matter to my design/architecture how is it done as long as the pri-key is set before it is added to your realm instance (as it can not be changed after...)). I'm not sure what Cristo was even imposing...(?).

    – SushiHangover
    Feb 12 at 21:22













  • It's just the error message that appeared when I tried to use OrderByDescending, I remember seeing things in the getting started guide that suggested that Realm didn't like classes that had inheritance

    – Assimilater
    Feb 12 at 21:31






  • 1





    @Assimilater Ahh... ok. Yes, you can not have multiple levels of inheritance of a RealmObject... You definitely have design your models around that, is it a pain, sure, I tend to hide that from the consumer of any RealmObject by using interfaces, but in the end you have to provide a concrete class that is stored in the realm instance.

    – SushiHangover
    Feb 12 at 21:38



















1





+50









Not sure why 'Max' doesn't work there. Realm.All() returns an IQueryable which inherits IEnumerable, so you should be able to use Max(). Are you sure that 'Max()' is throwing the NotSupportedException? What's the value that's being returned by 'All'? Can you post the exception message and stack trace?



An alternative to 'Max()' would be to order by descending and take element 0:



db.All<T>().OrderByDescending(el => el.Id).First();


If 'Max()' doesn't work, I wouldn't expect OrderByDescending to work either though. You might have to loop over All and find the max id the old fashioned way.



Another alternative would be 'ToList', then try the above or sort.



A fugly hack alternative to the way you're using IPrimaryKeyId is to have each DB class inherit from an abstract base object which has a private static id incremented int the ctor...



public interface IPrimaryKeyId
{
long Id { get; }
}

public abstract BankPrimaryKeyId : IPrimaryKeyId
{
private static long _id;
public long Id => _id;
protected BankPrimaryKeyId()
{
_id++;
}
}

public class Bank : BankPrimaryKeyId
{
}





share|improve this answer
























  • The static member would only work for as long as the program is running though. If the program is closed and opened again that tracking will be lost.

    – Assimilater
    Feb 12 at 20:50











  • I updated my question with responses to your other inquires. Thanks for taking the time to respond

    – Assimilater
    Feb 12 at 20:51











  • Attempting your OrderByDescending actually shed some light on the problem though: System.NotSupportedException: 'The class IPrimaryKeyId is not in the limited set of classes for this Realm, so sorting by its properties is not allowed.'

    – Assimilater
    Feb 12 at 20:53












Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54013820%2frealm-auto-incrementing-primary-key%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes









1















The problem is that on the line that calls Max() it throws a NotSupportedException




Assuming you have an int|long|... type as the primary key, you can use Last() on a transient query to obtain the last|max id value and manually increment it by one (since the Realm query is lazy loaded, only the last object is instanced to determine the current value of the primary key).



Example:



public class ItemModel : RealmObject
{
public ItemModel() { }

public ItemModel(int ID)
{
this.ID = ID;
}

[PrimaryKey]
public int ID { get; set; }

public static ItemModel Create()
{
ItemModel NewItemModel()
{
var q = Realm.GetInstance(Consts.realmDBName).All<ItemModel>();
return new ItemModel(q.Any() ? q.Last().ID + 1 : 0);
}

if (Realm.GetInstance(Consts.realmDBName).IsInTransaction)
{
return NewItemModel();
}
// Use a pseudo transaction to ensure multi-process safety on obtaining the last record
using (var trans = Realm.GetInstance(Consts.realmDBName).BeginWrite())
{
return NewItemModel();
}
}

}


Usage:



var aRealmObject = instance.Add(ItemModel.Create(), false);





share|improve this answer
























  • The Create function you put forward as an example would have to be copy pasted onto every class that inherits RealmObject, which is the reason I went towards implementing an interface. However the suggestion of Last I was able to bring into my solution and it appears to be working. I do wonder however if I will run into any problems down the road for reasons similar to the exception message I mentioned in comment to Cristo's answer: IPrimaryKeyId is not in the limited set of classes for this Realm. Thoughts?

    – Assimilater
    Feb 12 at 21:02











  • @Assimilater You do not have to copy/paste the static Create method into each model, you could create a Class Factory that automatically sets the primary key (based upon the same logic, just in a generic fashion..., I only expose the RealmObject inheritance as a model-based interface, so it really does not matter to my design/architecture how is it done as long as the pri-key is set before it is added to your realm instance (as it can not be changed after...)). I'm not sure what Cristo was even imposing...(?).

    – SushiHangover
    Feb 12 at 21:22













  • It's just the error message that appeared when I tried to use OrderByDescending, I remember seeing things in the getting started guide that suggested that Realm didn't like classes that had inheritance

    – Assimilater
    Feb 12 at 21:31






  • 1





    @Assimilater Ahh... ok. Yes, you can not have multiple levels of inheritance of a RealmObject... You definitely have design your models around that, is it a pain, sure, I tend to hide that from the consumer of any RealmObject by using interfaces, but in the end you have to provide a concrete class that is stored in the realm instance.

    – SushiHangover
    Feb 12 at 21:38
















1















The problem is that on the line that calls Max() it throws a NotSupportedException




Assuming you have an int|long|... type as the primary key, you can use Last() on a transient query to obtain the last|max id value and manually increment it by one (since the Realm query is lazy loaded, only the last object is instanced to determine the current value of the primary key).



Example:



public class ItemModel : RealmObject
{
public ItemModel() { }

public ItemModel(int ID)
{
this.ID = ID;
}

[PrimaryKey]
public int ID { get; set; }

public static ItemModel Create()
{
ItemModel NewItemModel()
{
var q = Realm.GetInstance(Consts.realmDBName).All<ItemModel>();
return new ItemModel(q.Any() ? q.Last().ID + 1 : 0);
}

if (Realm.GetInstance(Consts.realmDBName).IsInTransaction)
{
return NewItemModel();
}
// Use a pseudo transaction to ensure multi-process safety on obtaining the last record
using (var trans = Realm.GetInstance(Consts.realmDBName).BeginWrite())
{
return NewItemModel();
}
}

}


Usage:



var aRealmObject = instance.Add(ItemModel.Create(), false);





share|improve this answer
























  • The Create function you put forward as an example would have to be copy pasted onto every class that inherits RealmObject, which is the reason I went towards implementing an interface. However the suggestion of Last I was able to bring into my solution and it appears to be working. I do wonder however if I will run into any problems down the road for reasons similar to the exception message I mentioned in comment to Cristo's answer: IPrimaryKeyId is not in the limited set of classes for this Realm. Thoughts?

    – Assimilater
    Feb 12 at 21:02











  • @Assimilater You do not have to copy/paste the static Create method into each model, you could create a Class Factory that automatically sets the primary key (based upon the same logic, just in a generic fashion..., I only expose the RealmObject inheritance as a model-based interface, so it really does not matter to my design/architecture how is it done as long as the pri-key is set before it is added to your realm instance (as it can not be changed after...)). I'm not sure what Cristo was even imposing...(?).

    – SushiHangover
    Feb 12 at 21:22













  • It's just the error message that appeared when I tried to use OrderByDescending, I remember seeing things in the getting started guide that suggested that Realm didn't like classes that had inheritance

    – Assimilater
    Feb 12 at 21:31






  • 1





    @Assimilater Ahh... ok. Yes, you can not have multiple levels of inheritance of a RealmObject... You definitely have design your models around that, is it a pain, sure, I tend to hide that from the consumer of any RealmObject by using interfaces, but in the end you have to provide a concrete class that is stored in the realm instance.

    – SushiHangover
    Feb 12 at 21:38














1












1








1








The problem is that on the line that calls Max() it throws a NotSupportedException




Assuming you have an int|long|... type as the primary key, you can use Last() on a transient query to obtain the last|max id value and manually increment it by one (since the Realm query is lazy loaded, only the last object is instanced to determine the current value of the primary key).



Example:



public class ItemModel : RealmObject
{
public ItemModel() { }

public ItemModel(int ID)
{
this.ID = ID;
}

[PrimaryKey]
public int ID { get; set; }

public static ItemModel Create()
{
ItemModel NewItemModel()
{
var q = Realm.GetInstance(Consts.realmDBName).All<ItemModel>();
return new ItemModel(q.Any() ? q.Last().ID + 1 : 0);
}

if (Realm.GetInstance(Consts.realmDBName).IsInTransaction)
{
return NewItemModel();
}
// Use a pseudo transaction to ensure multi-process safety on obtaining the last record
using (var trans = Realm.GetInstance(Consts.realmDBName).BeginWrite())
{
return NewItemModel();
}
}

}


Usage:



var aRealmObject = instance.Add(ItemModel.Create(), false);





share|improve this answer














The problem is that on the line that calls Max() it throws a NotSupportedException




Assuming you have an int|long|... type as the primary key, you can use Last() on a transient query to obtain the last|max id value and manually increment it by one (since the Realm query is lazy loaded, only the last object is instanced to determine the current value of the primary key).



Example:



public class ItemModel : RealmObject
{
public ItemModel() { }

public ItemModel(int ID)
{
this.ID = ID;
}

[PrimaryKey]
public int ID { get; set; }

public static ItemModel Create()
{
ItemModel NewItemModel()
{
var q = Realm.GetInstance(Consts.realmDBName).All<ItemModel>();
return new ItemModel(q.Any() ? q.Last().ID + 1 : 0);
}

if (Realm.GetInstance(Consts.realmDBName).IsInTransaction)
{
return NewItemModel();
}
// Use a pseudo transaction to ensure multi-process safety on obtaining the last record
using (var trans = Realm.GetInstance(Consts.realmDBName).BeginWrite())
{
return NewItemModel();
}
}

}


Usage:



var aRealmObject = instance.Add(ItemModel.Create(), false);






share|improve this answer












share|improve this answer



share|improve this answer










answered Feb 12 at 19:03









SushiHangoverSushiHangover

54k54396




54k54396













  • The Create function you put forward as an example would have to be copy pasted onto every class that inherits RealmObject, which is the reason I went towards implementing an interface. However the suggestion of Last I was able to bring into my solution and it appears to be working. I do wonder however if I will run into any problems down the road for reasons similar to the exception message I mentioned in comment to Cristo's answer: IPrimaryKeyId is not in the limited set of classes for this Realm. Thoughts?

    – Assimilater
    Feb 12 at 21:02











  • @Assimilater You do not have to copy/paste the static Create method into each model, you could create a Class Factory that automatically sets the primary key (based upon the same logic, just in a generic fashion..., I only expose the RealmObject inheritance as a model-based interface, so it really does not matter to my design/architecture how is it done as long as the pri-key is set before it is added to your realm instance (as it can not be changed after...)). I'm not sure what Cristo was even imposing...(?).

    – SushiHangover
    Feb 12 at 21:22













  • It's just the error message that appeared when I tried to use OrderByDescending, I remember seeing things in the getting started guide that suggested that Realm didn't like classes that had inheritance

    – Assimilater
    Feb 12 at 21:31






  • 1





    @Assimilater Ahh... ok. Yes, you can not have multiple levels of inheritance of a RealmObject... You definitely have design your models around that, is it a pain, sure, I tend to hide that from the consumer of any RealmObject by using interfaces, but in the end you have to provide a concrete class that is stored in the realm instance.

    – SushiHangover
    Feb 12 at 21:38



















  • The Create function you put forward as an example would have to be copy pasted onto every class that inherits RealmObject, which is the reason I went towards implementing an interface. However the suggestion of Last I was able to bring into my solution and it appears to be working. I do wonder however if I will run into any problems down the road for reasons similar to the exception message I mentioned in comment to Cristo's answer: IPrimaryKeyId is not in the limited set of classes for this Realm. Thoughts?

    – Assimilater
    Feb 12 at 21:02











  • @Assimilater You do not have to copy/paste the static Create method into each model, you could create a Class Factory that automatically sets the primary key (based upon the same logic, just in a generic fashion..., I only expose the RealmObject inheritance as a model-based interface, so it really does not matter to my design/architecture how is it done as long as the pri-key is set before it is added to your realm instance (as it can not be changed after...)). I'm not sure what Cristo was even imposing...(?).

    – SushiHangover
    Feb 12 at 21:22













  • It's just the error message that appeared when I tried to use OrderByDescending, I remember seeing things in the getting started guide that suggested that Realm didn't like classes that had inheritance

    – Assimilater
    Feb 12 at 21:31






  • 1





    @Assimilater Ahh... ok. Yes, you can not have multiple levels of inheritance of a RealmObject... You definitely have design your models around that, is it a pain, sure, I tend to hide that from the consumer of any RealmObject by using interfaces, but in the end you have to provide a concrete class that is stored in the realm instance.

    – SushiHangover
    Feb 12 at 21:38

















The Create function you put forward as an example would have to be copy pasted onto every class that inherits RealmObject, which is the reason I went towards implementing an interface. However the suggestion of Last I was able to bring into my solution and it appears to be working. I do wonder however if I will run into any problems down the road for reasons similar to the exception message I mentioned in comment to Cristo's answer: IPrimaryKeyId is not in the limited set of classes for this Realm. Thoughts?

– Assimilater
Feb 12 at 21:02





The Create function you put forward as an example would have to be copy pasted onto every class that inherits RealmObject, which is the reason I went towards implementing an interface. However the suggestion of Last I was able to bring into my solution and it appears to be working. I do wonder however if I will run into any problems down the road for reasons similar to the exception message I mentioned in comment to Cristo's answer: IPrimaryKeyId is not in the limited set of classes for this Realm. Thoughts?

– Assimilater
Feb 12 at 21:02













@Assimilater You do not have to copy/paste the static Create method into each model, you could create a Class Factory that automatically sets the primary key (based upon the same logic, just in a generic fashion..., I only expose the RealmObject inheritance as a model-based interface, so it really does not matter to my design/architecture how is it done as long as the pri-key is set before it is added to your realm instance (as it can not be changed after...)). I'm not sure what Cristo was even imposing...(?).

– SushiHangover
Feb 12 at 21:22







@Assimilater You do not have to copy/paste the static Create method into each model, you could create a Class Factory that automatically sets the primary key (based upon the same logic, just in a generic fashion..., I only expose the RealmObject inheritance as a model-based interface, so it really does not matter to my design/architecture how is it done as long as the pri-key is set before it is added to your realm instance (as it can not be changed after...)). I'm not sure what Cristo was even imposing...(?).

– SushiHangover
Feb 12 at 21:22















It's just the error message that appeared when I tried to use OrderByDescending, I remember seeing things in the getting started guide that suggested that Realm didn't like classes that had inheritance

– Assimilater
Feb 12 at 21:31





It's just the error message that appeared when I tried to use OrderByDescending, I remember seeing things in the getting started guide that suggested that Realm didn't like classes that had inheritance

– Assimilater
Feb 12 at 21:31




1




1





@Assimilater Ahh... ok. Yes, you can not have multiple levels of inheritance of a RealmObject... You definitely have design your models around that, is it a pain, sure, I tend to hide that from the consumer of any RealmObject by using interfaces, but in the end you have to provide a concrete class that is stored in the realm instance.

– SushiHangover
Feb 12 at 21:38





@Assimilater Ahh... ok. Yes, you can not have multiple levels of inheritance of a RealmObject... You definitely have design your models around that, is it a pain, sure, I tend to hide that from the consumer of any RealmObject by using interfaces, but in the end you have to provide a concrete class that is stored in the realm instance.

– SushiHangover
Feb 12 at 21:38













1





+50









Not sure why 'Max' doesn't work there. Realm.All() returns an IQueryable which inherits IEnumerable, so you should be able to use Max(). Are you sure that 'Max()' is throwing the NotSupportedException? What's the value that's being returned by 'All'? Can you post the exception message and stack trace?



An alternative to 'Max()' would be to order by descending and take element 0:



db.All<T>().OrderByDescending(el => el.Id).First();


If 'Max()' doesn't work, I wouldn't expect OrderByDescending to work either though. You might have to loop over All and find the max id the old fashioned way.



Another alternative would be 'ToList', then try the above or sort.



A fugly hack alternative to the way you're using IPrimaryKeyId is to have each DB class inherit from an abstract base object which has a private static id incremented int the ctor...



public interface IPrimaryKeyId
{
long Id { get; }
}

public abstract BankPrimaryKeyId : IPrimaryKeyId
{
private static long _id;
public long Id => _id;
protected BankPrimaryKeyId()
{
_id++;
}
}

public class Bank : BankPrimaryKeyId
{
}





share|improve this answer
























  • The static member would only work for as long as the program is running though. If the program is closed and opened again that tracking will be lost.

    – Assimilater
    Feb 12 at 20:50











  • I updated my question with responses to your other inquires. Thanks for taking the time to respond

    – Assimilater
    Feb 12 at 20:51











  • Attempting your OrderByDescending actually shed some light on the problem though: System.NotSupportedException: 'The class IPrimaryKeyId is not in the limited set of classes for this Realm, so sorting by its properties is not allowed.'

    – Assimilater
    Feb 12 at 20:53
















1





+50









Not sure why 'Max' doesn't work there. Realm.All() returns an IQueryable which inherits IEnumerable, so you should be able to use Max(). Are you sure that 'Max()' is throwing the NotSupportedException? What's the value that's being returned by 'All'? Can you post the exception message and stack trace?



An alternative to 'Max()' would be to order by descending and take element 0:



db.All<T>().OrderByDescending(el => el.Id).First();


If 'Max()' doesn't work, I wouldn't expect OrderByDescending to work either though. You might have to loop over All and find the max id the old fashioned way.



Another alternative would be 'ToList', then try the above or sort.



A fugly hack alternative to the way you're using IPrimaryKeyId is to have each DB class inherit from an abstract base object which has a private static id incremented int the ctor...



public interface IPrimaryKeyId
{
long Id { get; }
}

public abstract BankPrimaryKeyId : IPrimaryKeyId
{
private static long _id;
public long Id => _id;
protected BankPrimaryKeyId()
{
_id++;
}
}

public class Bank : BankPrimaryKeyId
{
}





share|improve this answer
























  • The static member would only work for as long as the program is running though. If the program is closed and opened again that tracking will be lost.

    – Assimilater
    Feb 12 at 20:50











  • I updated my question with responses to your other inquires. Thanks for taking the time to respond

    – Assimilater
    Feb 12 at 20:51











  • Attempting your OrderByDescending actually shed some light on the problem though: System.NotSupportedException: 'The class IPrimaryKeyId is not in the limited set of classes for this Realm, so sorting by its properties is not allowed.'

    – Assimilater
    Feb 12 at 20:53














1





+50







1





+50



1




+50





Not sure why 'Max' doesn't work there. Realm.All() returns an IQueryable which inherits IEnumerable, so you should be able to use Max(). Are you sure that 'Max()' is throwing the NotSupportedException? What's the value that's being returned by 'All'? Can you post the exception message and stack trace?



An alternative to 'Max()' would be to order by descending and take element 0:



db.All<T>().OrderByDescending(el => el.Id).First();


If 'Max()' doesn't work, I wouldn't expect OrderByDescending to work either though. You might have to loop over All and find the max id the old fashioned way.



Another alternative would be 'ToList', then try the above or sort.



A fugly hack alternative to the way you're using IPrimaryKeyId is to have each DB class inherit from an abstract base object which has a private static id incremented int the ctor...



public interface IPrimaryKeyId
{
long Id { get; }
}

public abstract BankPrimaryKeyId : IPrimaryKeyId
{
private static long _id;
public long Id => _id;
protected BankPrimaryKeyId()
{
_id++;
}
}

public class Bank : BankPrimaryKeyId
{
}





share|improve this answer













Not sure why 'Max' doesn't work there. Realm.All() returns an IQueryable which inherits IEnumerable, so you should be able to use Max(). Are you sure that 'Max()' is throwing the NotSupportedException? What's the value that's being returned by 'All'? Can you post the exception message and stack trace?



An alternative to 'Max()' would be to order by descending and take element 0:



db.All<T>().OrderByDescending(el => el.Id).First();


If 'Max()' doesn't work, I wouldn't expect OrderByDescending to work either though. You might have to loop over All and find the max id the old fashioned way.



Another alternative would be 'ToList', then try the above or sort.



A fugly hack alternative to the way you're using IPrimaryKeyId is to have each DB class inherit from an abstract base object which has a private static id incremented int the ctor...



public interface IPrimaryKeyId
{
long Id { get; }
}

public abstract BankPrimaryKeyId : IPrimaryKeyId
{
private static long _id;
public long Id => _id;
protected BankPrimaryKeyId()
{
_id++;
}
}

public class Bank : BankPrimaryKeyId
{
}






share|improve this answer












share|improve this answer



share|improve this answer










answered Feb 12 at 17:20









ChristoChristo

28415




28415













  • The static member would only work for as long as the program is running though. If the program is closed and opened again that tracking will be lost.

    – Assimilater
    Feb 12 at 20:50











  • I updated my question with responses to your other inquires. Thanks for taking the time to respond

    – Assimilater
    Feb 12 at 20:51











  • Attempting your OrderByDescending actually shed some light on the problem though: System.NotSupportedException: 'The class IPrimaryKeyId is not in the limited set of classes for this Realm, so sorting by its properties is not allowed.'

    – Assimilater
    Feb 12 at 20:53



















  • The static member would only work for as long as the program is running though. If the program is closed and opened again that tracking will be lost.

    – Assimilater
    Feb 12 at 20:50











  • I updated my question with responses to your other inquires. Thanks for taking the time to respond

    – Assimilater
    Feb 12 at 20:51











  • Attempting your OrderByDescending actually shed some light on the problem though: System.NotSupportedException: 'The class IPrimaryKeyId is not in the limited set of classes for this Realm, so sorting by its properties is not allowed.'

    – Assimilater
    Feb 12 at 20:53

















The static member would only work for as long as the program is running though. If the program is closed and opened again that tracking will be lost.

– Assimilater
Feb 12 at 20:50





The static member would only work for as long as the program is running though. If the program is closed and opened again that tracking will be lost.

– Assimilater
Feb 12 at 20:50













I updated my question with responses to your other inquires. Thanks for taking the time to respond

– Assimilater
Feb 12 at 20:51





I updated my question with responses to your other inquires. Thanks for taking the time to respond

– Assimilater
Feb 12 at 20:51













Attempting your OrderByDescending actually shed some light on the problem though: System.NotSupportedException: 'The class IPrimaryKeyId is not in the limited set of classes for this Realm, so sorting by its properties is not allowed.'

– Assimilater
Feb 12 at 20:53





Attempting your OrderByDescending actually shed some light on the problem though: System.NotSupportedException: 'The class IPrimaryKeyId is not in the limited set of classes for this Realm, so sorting by its properties is not allowed.'

– Assimilater
Feb 12 at 20:53


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54013820%2frealm-auto-incrementing-primary-key%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

MongoDB - Not Authorized To Execute Command

How to fix TextFormField cause rebuild widget in Flutter

in spring boot 2.1 many test slices are not allowed anymore due to multiple @BootstrapWith