Java 使用objectify的多对多关系?

Java 使用objectify的多对多关系?,java,google-app-engine,objectify,Java,Google App Engine,Objectify,我正在将我的应用程序从关系数据库移动到objectify/google应用程序引擎 应用程序具有如下建模的关系: 一条消息可以发送给许多用户。每个用户都可以收到许多消息s 我需要能够扫描发送给特定用户的所有消息 如何使用Objectify实现这一点?有多种方法 您可以在用户对象中保存消息列表。这将很好地满足您将所有消息发送给用户的需求,因为不需要进行查询 您可以在消息对象中保存用户列表。要获取所有发送给单个用户的消息,请执行查询 您可以保存上面的两个列表。请记住,在应用程序引擎中,通常不需要规范

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

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

一条
消息
可以发送给许多
用户
。每个
用户
都可以收到许多
消息
s

我需要能够扫描发送给特定
用户的所有
消息


如何使用Objectify实现这一点?

有多种方法

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

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

  • 您可以保存上面的两个列表。请记住,在应用程序引擎中,通常不需要规范化,也不需要担心磁盘空间和副本。几乎总是构建您的结构,以便查询速度更快

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


  • 最重要的变量将决定在您指定的查询中采用哪种方法,即通常向单个用户发送多少条消息,以及消息的最大数量?如果我们说的是平均几十条或更少,最多几百条,那么用户对象中的消息列表在我看来是一个不错的选择。如果我们谈论的是更多,尤其是无限的话,那么它就不能很好地工作,您需要进行实际的查询。

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

    Objectify Wiki(多值关系)建议的方法是保留键的集合(或数组)

    公共类消息
    {
    @Id字符串时间戳;
    键[]目的地;
    }
    公共类用户
    {
    @Id字符串名称;
    关键字[]收件箱;
    }
    

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

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

    • GAE中的藏品严格限制为5000件。一旦用户的收件箱超过5k个项目,你的应用程序就会开始抛出异常

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

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

    如果一封邮件的收件人限制为5000人,那么在邮件中存储目标密钥集(并为该集编制索引,以便查询用户的所有邮件)可能是一个很好的解决方案。几乎可以肯定的是,将消息分配给发送者的@Parent也有好处


    如果你是推特,并希望消息有超过5K的接收者,或者如果你的消息通常有很多接收者(因此消息实体被臃肿),你可能会考虑Brett Slatkin在谷歌I/O会话中从2009:“/P>+ 1”中谈到的关系索引实体模式。这里的关键是改变对

    消息的感知:在RDBMS中,您将消息视为一条绝对的“信息”,通过查询与用户连接。在数据存储中,用户拥有一份邮件副本,就像电子邮件一样:在你的Gmail帐户中,你不在乎发件人是否在发送邮件后删除邮件,一旦你收到邮件,你实际上“拥有”了一份与发件人断开连接的副本。要“发送”一封
    邮件
    ,您必须将一份副本放入发件人的“已发送”框和收件人的“收件箱”框中。谢谢您的提示。我预计每封邮件的收件人不到5000人。但是我怎样才能让邮件成为发件人的父级呢?你的意思不是相反吗?因为一旦有人创建了一条消息,它将始终来自他们,而不能来自其他任何人。似乎,如果项目超过5000,创建另一个实体来存储关系是最好的解决方案(类似于关系数据库映射表)
    public class Message
    {
        @Id String timeStamp;
        Key<User>[] destination;
    }
    
    public class User
    {
        @Id String name;
        Key<Message>[] inbox;
    }