【问题标题】:Is it possible to use a RealmObject in a ViewModel, after disposing the Realm?处置领域后,是否可以在 ViewModel 中使用领域对象?
【发布时间】:2018-07-13 23:42:01
【问题描述】:

我正在考虑在我的 UWP 应用程序中从 SQLite 切换到 Realm,因为 Realm 似乎相当容易设置,但我遇到了一些限制,到目前为止对我来说是一个交易破坏者,最重要的是显然,在处理用于检索它们的 Realm 实例之后,您不能使用领域对象。所以我想知道我应该如何加载数据以放入 ViewModel,因为在加载了 Realm 实例将消失的数据项之后。

这是一个非常基本的 ViewModel 示例:

public class MyViewModel : ViewModelBase // Assume this has INotifyPropertyChanged setup
{
    private IEnumerable<MyItem> _Items;

    public IEnumerable<MyItem> Items
    {
        get => _Items;
        private set => Set(nameof(Items), ref _Items, value);
    }

    public async Task LoadDataAsync()
    {
        using (Realm realm = await Realm.GetInstanceAsync())
        {
            Items = realm.All<MyItem>().ToArray();
        }
    }
}

假设MyItem 是一些示例模型,它继承自RealmObject

现在,如果我使用 SQLite,我将不会有任何问题,因为一旦从数据库中检索到,每个模型实例都将是一个独立的对象,我可以将其存储在我的 ViewModel 中。相反,从 RealObject 继承的类链接到它们原来的 Realm 实例,所以如果我在源 Realm 实例被处理后尝试使用它们(即读取它们的属性之一),一切都会崩溃(我得到了一个不错的Exception)。

显而易见的解决方法是为每个模型保留两个类:一个映射到 Realm 数据库,另一个是独立对象。但这有一些缺点:

  • 课程数量翻倍
  • 将每个实例复制到独立类的额外工作(和内存浪费)
  • 这似乎是错误的,我的意思是,来吧

另一种可能性是保留一个永远不会关闭的 Realm 对象的单例实例,但听起来也不是一个好主意(而且在使用多个线程时也会出现问题,所以它绝对不是有效的解决方案)。

我已经看到 Realm 库的 Java 版本有一些“getRawObject”方法(或类似的方法),可以让您获得 RealmObject 的独立副本,但我想这实际上创建了一个模型实例的副本,所以听起来也不好。

我的问题是:

有没有办法获得与 SQLite 相同的灵活性,一旦加载,您可以将模型传递到您想要的任何地方(包括其他线程),在 ViewModels 中使用它们,然后最终编辑它们并传递它们回到数据库以在磁盘上更新它们?

加分项:作为另一个例子,考虑一个从 Realm 数据库加载一些项目并将它们返回给用户的库。加载后,这些对象将是只读的,这意味着即使以某种方式对其进行了修改,也不会在数据库本身上对其进行更改。我当前的解决方案是再次将每个加载的模型复制到另一个不继承自 RealmObject 的类中,但正如我所说,这根本不可扩展(想象一个有几十个模型的大型项目,这是不可能的所以)。

【问题讨论】:

标签: c# .net mvvm uwp realm


【解决方案1】:

在 .NET 中,似乎只有当您以某种方式创建托管 RealmObject 的副本时,才能将托管 RealmObject 从 Realm 中分离出来。

https://stackoverflow.com/a/38061292/2413303

public Contact ToStandalone()
{
    return new Contact()
    {
        companyName = this.companyName,
        dateAdded = this.dateAdded,
        fullName = this.fullName,
        gender = this.gender,
        website = this.website
    };
}

从技术上讲,它不必是不同的类,但需要使用 new 创建。

至于必须制作副本 - 嗯,这也是您使用 SQLite 时常做的事情。

【讨论】:

  • 好吧,这样好一点,至少我可以复用同一个类。不过,我将来肯定会坚持使用 SQLite,因为这种方法不可扩展(除了不能从 RealObject 间接继承的缺点之外,您必须为每个类手动实现一个复制方法)。另外,我不确定我是否理解您所说的“这也是您对 SQLite 所做的事情”的意思。在那里我可以从数据库中加载模型并在任何地方使用它们(如果我想更新它们并将它们传回),我会在哪里制作副本?
  • 诀窍是 Realm-java 通过注解处理生成这种映射。我猜dot-net版本没有。我所说的复制的意思是您应该将 RealmObject 类视为模式定义(CREATE TABLE blah blah)。所以在 SQLite 中,你有一个 SQL 模式,但在 Realm 中,你的对象是模式。附加对象在技术上仍然属于 Realm 世界。因此,当您从 SQLite 映射到实际实体时,就像将托管映射到非托管一样。除了 Realm 允许直接使用模式对象(托管),这提供了延迟加载和观察能力。
  • 这与我在 SQLite 中的模式完全相同(在 SQLite.NET lib 中),我的意思是由类似 EntityFramework 的引擎提供支持的版本。因此,您只需使用属性将您的属性映射到表列(类似于 Realm),然后所有查询和数据库操作都由库处理,您只需传递 LINQ Expressions 并将它们转换为查询并映射回对象。但是,模型实例在那里是 100% 独立的,也没有绑定到线程,所以它更灵活。此外,您可以毫无问题地进行间接继承(与 RealmObject 不同)。
  • 无论如何,我将答案标记为有效,因为它实际上很好地回答了我的问题?另外,我不确定您是否真的在 Realm 团队工作,我只想说我根本没有批评 lib 本身,而是非常棒,我只是在考虑限制,至少在 .NET 版本的 lib 上(我知道很难平衡易于使用的 API 用于通用用途和更多功能)。
  • 没有开箱即用的支持从领域中“分离”一个对象,因为这是一个定义不明确的通用要求。例如,如果您的对象具有其他对象的集合 - 这些对象是否也应该被分离?然后,如果有循环,是否应该为您解决它们等等。有许多专门用于将一个对象映射到另一个对象的工具,例如AutoMapper,它将为您省去手动复制对象的痛苦。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-02
  • 1970-01-01
相关资源
最近更新 更多