【问题标题】:many to many relationship using objectify?使用objectify的多对多关系?
【发布时间】:2014-05-14 07:20:14
【问题描述】:

我正在将我的应用程序从关系数据库移动到 objectify / google app engine。

应用程序具有如下建模的关系:

一个Message 可以发送给多个Users。每个User 可以有多个Messages 发给他们。

我需要能够扫描发往特定User 的所有Messages。

我如何使用 Objectify 做到这一点?

【问题讨论】:

    标签: java google-app-engine objectify


    【解决方案1】:

    有很多方法可以做到这一点。

    1. 您可以在用户对象中保存消息列表。这将很好地满足您将所有消息发送给用户的要求,因为无需进行查询。

    2. 您可以在消息对象中保存用户列表。要获取发送给单个用户的所有消息,请执行查询。

    3. 您可以保存以上两个列表。请记住,在 App Engine 中,通常不需要规范化和担心磁盘空间和重复项。几乎总是构建您的结构,以便快速查询。

    4. 您可以忘记列表,而拥有关系对象,就像关系数据库中的表一样。在某些用例中,它仍然是 App Engine 中的不错选择,例如,当列表太大(数千个)并且会使您的对象膨胀甚至可能无法查询时。

    决定针对您指定的查询采取哪种方法的最重要变量是,通常有多少条消息会发送给单个用户,以及是否有最大数量的消息?如果我们谈论的是平均几十个或更少,最多几百个,那么用户对象中的消息列表对我来说是一个不错的选择。如果我们谈论更多,特别是如果无限,它不会那么好用,您需要进行实际查询。

    【讨论】:

    • +1,这里的关键是改变对Message 的看法:在RDBMS 中,您会将您的消息视为您通过查询连接到用户的绝对“信息片段”。使用数据存储,用户拥有邮件的副本,例如电子邮件:使用您的 Gmail 帐户,您不必在意发件人在发送后是否删除了电子邮件,一旦您收到电子邮件,您实际上“拥有”一份副本与发件人断开连接。要“发送”Message,您必须将副本实际放入发件人“已发送”篮子和收件人“收件箱”篮子。
    【解决方案2】:

    除了已经发布的答案之外,我建议您不要包含从用户到消息的链接,原因有以下三个:

    • GAE 中的集合被硬限制为 5000 个项目。一旦您用户的收件箱超过 5k 项,您的应用就会开始抛出异常。

    • 扩展实体中的数据量会产生性能成本;加载一堆 500k 实体比加载一堆 5k 实体慢。另外,您对 memcache 的使用效率会降低,因为您可以在同一空间中容纳更少的项目。用户对象往往会被加载很多

    • 您可以轻松达到单个实体的事务速率限制 (1/s)。如果 50 个人同时向您发送消息,您将遇到大量并发问题,因为所有 50 人都以乐观的失败重试。

    如果您可以忍受单个消息的 5000 个收件人的限制,那么将目标键集合存储在消息中(并对该集合进行索引以便您可以查询用户的所有消息)可能是一个很好的解决方案。几乎可以肯定,将消息分配给发件人的@Parent 也是一个优势。

    如果您喜欢 twitter 并希望消息有超过 5k 的收件人,或者如果您的消息通常有很多收件人(因此消息实体臃肿),您可能希望考虑关系索引实体模式Brett Slatkin 在 2009 年的 Google I/O 演讲中谈到:https://www.youtube.com/watch?v=AgaL6NGpkB8

    【讨论】:

    • 感谢您的提示。我预计每封邮件的收件人数少于 5000。但是我怎样才能让消息成为发件人的父母?你不是说反过来吗?因为一旦有人创建了一条消息,它将始终来自他们,而不能来自其他任何人。
    • 似乎如果超过5000个,再创建一个实体来存储关系是最好的解决方案(就像关系数据库映射表)
    【解决方案3】:

    你必须自己维持这种关系。这是因为根据应用程序,让用户在没有消息的情况下存在是有意义的,甚至相反。

    Objectify Wiki (https://code.google.com/p/objectify-appengine/wiki/IntroductionToObjectify Multi-Value Relations) 建议的方法是保留键的集合(或数组)

    public class Message
    {
        @Id String timeStamp;
        Key<User>[] destination;
    }
    
    public class User
    {
        @Id String name;
        Key<Message>[] inbox;
    }
    

    然后,如果您想在删除用户时删除所有用户消息,只需在用户之前将它们从数据存储中删除即可。如果您想为特定用户添加新消息,也完全相同。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-10-11
      • 2012-02-27
      • 2021-11-05
      • 1970-01-01
      • 1970-01-01
      • 2018-06-15
      • 2016-02-02
      相关资源
      最近更新 更多