针对不同对象的多个领域查询

Posted

技术标签:

【中文标题】针对不同对象的多个领域查询【英文标题】:Multiple Realm queries for different Objects 【发布时间】:2018-07-23 09:05:24 【问题描述】:

我想创建一个返回Results<A> 类型对象的整个数据库搜索。我有一个类A 继承自领域Object,然后还有许多其他类继承自该子类。像这样的:

class A: Object 
protocol Z 
class B: A, Z 
class C: A, Z 
class D: A, Z 
...

现在我想同时查询不同的类,我正在做这样的事情:

private func getResults<T: A>(withTypes types: [T.Type]) 
  for type in types 
    let foundIds = getRealm().objects(type).filter(aPredicate)
    ids.append(contentsOf: foundIds)
  

  // Do something with all those ids

我这样称呼它:

getResults(withTypes: [B.self, C.self, D.self])

问题是 Realm 不喜欢多态性,一旦我在调用函数时在数组中添加多个类类型,它就会崩溃,因为数组的推断类型是 A.self 而不是每个中的单个元素数组的位置。过滤是通过使用A 不符合的Z 协议变量完成的 - 它不应该符合 - 但对象的其余部分确实符合它。所以这行得通:

getResults(withTypes: [C.self])

或者这个:

getResults(withTypes: [D.self])

因为Array 的推断类型是C.selfD.self,而不是推断的通用A.self

我想指出,在数据库中没有任何A 对象,它只是所有其他对象的超类。

如何创建多重搜索?

我认为我可以创建一种可搜索的对象并对其进行查询,但我管理的数据库很大,我不知道这是否会对系统的性能产生重大影响。

提前致谢!

【问题讨论】:

【参考方案1】:

在您的查询中,如果您只对获取 id 并将它们附加到数组感兴趣,您可以将它们映射到 ids.append(contentsOf: foundIds.map( $0.idFromZProtocol ))。但这会禁用 Realm 的延迟加载,因为所有对象都会被访问。

你也可以做其他方式:

假设 A 是动物,B 是狗,C 是鸟,D 是猫。 您正在寻找所有的绿色动物。

你可以拥有

Animal
@objc dynamic var dog: Dog?
@objc dynamic var bird: Bird?
@objc dynamic var cat: Cat?

Bird, Cat, Dog
@objc dynamic var color: String
@objc dynamic var legNumber: Int

let predicate = "dog.color == Green || bird.color == Green || cat.color == Green"
getRealm().objects(Animal.self).filter(predicate)

您可以在 Animal 上处理一个变量,通过检查哪个变量不是 nil 来判断它是猫、狗还是鸟。您还可以将 Z 协议分配给 Dog、Cat 和 Bird 以执行 Animal.color 而不是猜测 Animal.dog?.colorAnimal.cat?.color

通过这种方法,您可以保留 Realm 的延迟加载功能,如果您有一个非常大的 Realm 文件,这非常好。

【讨论】:

不幸的是,这不是一个最佳解决方案,因为我有 50 多个不同的 A 子类,正如我所说,A 没有存储在数据库中。因此,即使我认为 A -dirty 中有该结构,我也无法搜索该特定对象,因为它不存在。如果我必须存储A 才能做到这一点,我可以创建一个Search 实体用于搜索,该实体将包含我想要搜索的领域对象的id。所以我会存储一个新对象Search 而不是A,并且我会避免在A 中创建所有这些变量。 哦,我错过了 A 不在 DB 中的那部分。那么在这种情况下,这是不可能的。您需要通过执行类似于我建议的操作(例如 CPU 高效)来重新考虑您的数据库架构。它可能很脏,这就是为什么你需要创建一个顶层来清理它并且只使用那个顶层。或者您必须通过手动获取所有对象并手动合并来完成所有处理。它不能是 Result(它是直接映射到 Realm DB,所以 A 需要在那里),但将是一个满载的 Array。 是的,我明白了......也许最好的方法就是你所说的。将A 保存到数据库并使其扩展协议并避免在A 中创建所有这些变量。 你总是可以选择 SQLite,它可能更符合你在模式方面的需求。 我们已经有了一个非常大的产品,并且改变它会花费我们很多钱,我们不能浪费在这上面......但是感谢您的帮助:)

以上是关于针对不同对象的多个领域查询的主要内容,如果未能解决你的问题,请参考以下文章

多个领域来处理 Spring MVC 和 shiro 中不同 url 集的身份验证

一文告诉你什么是领域驱动设计?

如何针对单个应用程序对来自不同领域的用户进行身份验证?

领域链接对象和删除

什么是DDD(领域驱动设计)?

保存对象时从错误线程访问的领域