【问题标题】:How to deal with a Many-To-Many Relation in my API如何在我的 API 中处理多对多关系
【发布时间】:2008-11-22 18:39:57
【问题描述】:

我有两个实体 Foo 和 Bar,它们之间存在多对多关系。

假设对于为什么 Foo 可能对多对多关系“负责”没有语义论据,但我们任意决定 Foo 负责该关系(即,在 NHibernate 中,我们将 Bar 标记为 Inverse)

从数据库的角度来看,这一切都很好,但我的实体 API 揭示了一个问题。

    // Responsible for the relation
    public class Foo
    {
        List<Bar> Bars = new List<Bar>();

        public void AddBar(Bar bar)
        {
            Bars.Add(bar);
            bar.AddFoo(this);
        }
    }

    public class Bar
    {
        List<Foo> Foos = new List<Foo>();

        // This shouldn't exist.
        public void AddFoo(Foo foo)
        {
            Foos.Add(foo);
            foo.AddBar(this); // Inf Recursion
        }
    }

如果我们确定 Foo 负责这种关系,我如何在不创建甚至不应该存在的公共 Bar.AddFoo() 方法的情况下更新 Bar 中的关联集合?

我觉得我应该能够保持我的域模型的完整性,而不必在这样的操作之后从数据库中重新加载这些实体。

更新:受评论者启发的代码调整。

【问题讨论】:

    标签: nhibernate api many-to-many entity entity-relationship


    【解决方案1】:

    您可能在那里遗漏了一个域概念。您是否尝试过创建第三个实体:FooBarRelationship?

    【讨论】:

    • 有时这是合适的,有时是矫枉过正。 NH 将允许您存储一些基本数据来捕获关系,即使不创建另一个实体。建议 +1。
    • 如果我有一些其他信息可以与这段关系一起拖,我可能会这样做,但目前我犹豫要添加,因为我没有这样的额外信息。跨度>
    【解决方案2】:

    请参阅 Hibernate 文档中的 Working bi-directional links

    许多开发人员进行防御性编程 并创建链接管理方法以 正确设置两侧,例如在 人:

    protected Set getEvents() {
        return events;
    }
    
    protected void setEvents(Set events) {
        this.events = events;
    }
    
    public void addToEvent(Event event) {
        this.getEvents().add(event);
        event.getParticipants().add(this);
    }
    
    public void removeFromEvent(Event event) {
        this.getEvents().remove(event);
        event.getParticipants().remove(this);
    }
    

    我个人认为Entity对象持有相关对象列表太聪明了,你应该让DAL打数据库。

    DALFactory.FooAdapter.getBars(foo);
    

    【讨论】:

      【解决方案3】:

      你说过一方将“拥有”这种关系。将此方法公开。其他关联(或添加方法)可以在内部进行,以避免消费者直接与其交互。

      public class Foo
      {  
         private IList<Bar> Bars {get;set;}
      
         public void AddBar(Bar bar)
         {
            Bars.Add(bar);
            bar.Foos.Add(this);
         }
      }
      
      public class Bar
      {
         internal IList<Foo> Foos {get;set;}
      }
      

      【讨论】:

      • 实际上,如果 Foo 必须是公共的以便消费者可以使用它,那么将其公开为一些不可变集合并使用内部的 AddFoo() 方法。
      • 我的集合是不可变的,我只是不想打扰示例中的所有混乱。我一直在回去使用 internal 清理一些域,我认为这确实有帮助......我们会看看它是如何工作的。
      【解决方案4】:

      你可以把它变成静态的

      public class Foo
      {
          List<Bar> Bars = new List<Bar>();
      
          public void AddBar(Bar bar)
          {
              Bars.Add(bar);
              Bar.AddFoo(bar,this);
          }
      }
      
      public class Bar
      {
          List<Foo> Foos = new List<Foo>();
      
          // This shouldn't exist.
          public static void AddFoo(Bar bar, Foo foo)
          {
              bar.Foos.Add(foo);
              //foo.AddBar(this); inf recurtion
          }
      }
      

      不是很理想,但它确实从对象自身中获取了功能

      【讨论】:

        猜你喜欢
        • 2011-09-13
        • 1970-01-01
        • 2021-01-08
        • 1970-01-01
        • 2021-01-28
        • 2020-10-09
        • 2018-09-17
        相关资源
        最近更新 更多