我正在通过实现一个简单的财务簿记工具来试用Realm。我正在使用类似于以下内容的架构(从基于sql的项目继承)
最初,我为所有这些表设置类,类型为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()
。所以现在我剩下一些潜在的问题要解决,任何一个问题都会使我前进。
NotSupportedException
来确定最大值Max()
Id
并一起放弃ID的功效这对我来说已经成为领域的习惯,所以我要尽可能以“领域方式”做事。欢迎就我如何更好地适应这种风格发表其他评论。
在上面的代码片段中可以看到,有问题的异常被调用的行是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(
的行
答案 0 :(得分:1)
不知道为什么“ Max”在那里不起作用。 Realm.All()返回一个继承IQueryable的IEnumerable,因此您应该可以使用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);