领域:自动递增主键

时间:2019-01-02 22:08:23

标签: c# .net realm

我正在通过实现一个简单的财务簿记工具来试用Realm。我正在使用类似于以下内容的架构(从基于sql的项目继承)

Example Schema

最初,我为所有这些表设置类,类型为PrimaryKey的{​​{1}}。然后,我至少在2015年才了解到doesn't support auto-increment域。在我自己的测试中,这似乎是真的,因为我得到一个例外,说long是重复的主键。

看看getting started guide上的示例,我尝试重新评估是否确实需要特定的ID字段。在大多数情况下,除了在数据库中使用主键可能带来的速度优势外,我似乎并没有特别注意。但是对我而言,可以期望在我建立关系时Realm在后台进行此操作似乎很合理。不过有一个例外。

0

起初,我考虑过让Transaction具有一个// 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); } } } } 字段,但是我不喜欢将一个条目添加到两个条目中所带来的好处。不得不维护数据的单独副本对我来说并不有吸引力。我考虑过不要使用IList<Transaction>函数来比较ID,因为我注意到Equals重载了它(类似RealmObject),但是我不确定它在查询中的处理方式(也许我应该在发布此问题后尝试一下...但是我距离能够进行测试还有一点距离)

好吧,在这一点上(我可能错了),看来对我来说最好实现自动增量。因此,按照afore-mentioned stack overflow post中的示例,我想到了一些东西。

tl => tl.Rhs.Equals(this)

afore-mentioned guide说,领域不喜欢这些类中的继承,但是在这个简单的界面看来运行起来还不错。问题是在调用// 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); }); } } } 的行上它抛出了Max()。所以现在我剩下一些潜在的问题要解决,任何一个问题都会使我前进。

  1. 替代NotSupportedException来确定最大值Max()
  2. 验证在Linq查询中使用Id并一起放弃ID的功效
  3. 我没考虑过的另一种选择

这对我来说已经成为领域的习惯,所以我要尽可能以“领域方式”做事。欢迎就我如何更好地适应这种风格发表其他评论。

回复@Cristo

在上面的代码片段中可以看到,有问题的异常被调用的行是Equals(this)。确切的文本是long id = db.All<T>().Max(el => el.Id);。堆栈跟踪为

System.NotSupportedException: 'The method 'Max' is not supported'

第47行对应于[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] ,第48行对应于调用db.Write(的行

2 个答案:

答案 0 :(得分:1)

不知道为什么“ Max”在那里不起作用。 Realm.All()返回一个继承IQueryableIEnumerable,因此您应该可以使用Max()。您确定'Max()'抛出NotSupportedException吗? “全部”返回的值是什么?您可以发布异常消息和堆栈跟踪吗?

“ Max()”的另一种选择是按降序排列并取元素0:

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

如果'Max()'不起作用,我也不希望OrderByDescending也能起作用。您可能必须遍历All并以老式方式找到最大id。

另一种选择是“ ToList”,然后尝试上面的方法或排序。

一种使用IPrimaryKeyId的方式的丑陋替代方法是让每个DB类从抽象基础对象继承,该抽象基础对象的私有静态ID随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
{
}

答案 1 :(得分:1)

  

问题在于,在调用Max()的行上,它引发了NotSupportedException

假设,您有int | long | ...类型作为主键,则可以在瞬态查询中使用Last()来获取last | max id值并手动递增(由于Realm查询是延迟加载的,因此仅实例化最后一个对象以确定主键的当前值)。

示例:

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();
        }
    }

}

用法:

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