如何在代码中建模多对多关系?

假设我在数据库中有2个表。 例如:Dog&Boss这是一个多对多的关系,因为老板可以拥有超过1只狗,而一只狗可以有超过1只拥有者。 我是Bobby的老板,但我的妻子也是。

但是很多人不允许这样做,所以有一个很好的帮助:DogsPerBoss

如何在代码中建模?

class老板可以拥有一系列狗。 Class Dog可以拥有一系列老板。 – >至少,这就是我的想法。 也许有更好的解决方案?

辅助表中的额外数据怎么样? 这应该是de Boss-class还是Dog-class? 例如:昵称(我叫狗“好孩子”,我的妻子称他为“小狗”)

我希望我的问题有点清楚吗? 有什么最好的方法来实现这个目标是什么? 你能给我一些参考吗?

ORM(如NHibernate)不是一个选项。

你为什么要谈论桌子? 您是在创建对象模型还是数据库模型?

对于对象模型,Dog没有理由不能拥有List ,并且拥有者拥有List 。 只有在关系上有属性时才需要中间类(UML称为关联类)。 那时候你有一个带有额外属性的DogOwnership类,每个所有者都会有一个List ,每只Dog都会这样。 DogOwner将拥有狗,所有者和额外的财产。

 public class Boss { private string name; private List dogs; private int limit; public Boss(string name, int dogLimit) { this.name = name; this.dogs = new List(); this.limit = dogLimit; } public string Name { get { return this.name; } } public void AddDog(string nickname, Dog dog) { if (!this.dogs.Contains(nickname) && !this.dogs.Count == limit) { this.dogs.Add(nickname, dog); dog.AddBoss(this); } } public void RemoveDog(string nickname) { this.dogs.Remove(nickname); dog.RemoveBoss(this); } public void Hashtable Dogs { get { return this.dogs; } } } public class Dog { private string name; private List bosses; public Dog(string name) { this.name = name; this.bosses = new List(); } public string Name { get { return this.name; } } public void AddBoss(Boss boss) { if (!this.bosses.Contains(boss)) { this.bosses.Add(boss); } } public void RemoveBoss(Boss boss) { this.bosses.Remove(boss); } public ReadOnlyCollection Bosses { get { return new ReadOnlyCollection(this.bosses); } } } 

以上保持了老板的关系可以有多只狗(有限制)和有多个老板的狗。 这也意味着当老板添加狗时,他们可以为狗指定一个昵称,该昵称仅对该老板是唯一的。 这意味着其他老板可以添加相同的狗,但具有不同的昵称。

至于限制,我可能会将此作为App.Config值,您在实例化boss对象之前就读到了该值。 所以一个小例子是:

 var james = new Boss("James", ConfigurationManager.AppSettings["DogsPerBoss"]); var joe = new Boss("Joe", ConfigurationManager.AppSettings["DogsPerBoss"]); var benji = new Dog("Benji"); var pooch = new Dog("Pooch"); james.AddDog("Good boy", benji); joe.AddDog("Doggy", benji); james.AddDog("Rover", pooch); joe.AddDog("Buddy", pooch); // won't add as the preset limit has been reached. 

你可以在你认为合适的情况下调整它,但是,我认为你所寻找的基本原理是存在的。

  • 老板可以有多只限量的狗
  • 狗可以有多个老板
  • 老板可以为同一只狗提供不同的昵称。

像这样的东西; 它仍然需要一些微调(使集合私有,并为它添加一个只读公共访问器,例如返回readonlycollection,但你会发现漂移。

 public class Dog { public List Bosses; public void AddBoss( Boss b ) { if( b != null && Bosses.Contains (b) == false ) { Bosses.Add (b); b.AddDog (this); } } public void RemoveBoss( Boss b ) { if( b !=null && Bosses.Contains (b) ) { Bosses.Remove (b); b.RemoveDog (this); } } } public class Boss { public List Dogs; public void AddDog( Dog d ) { if( d != null && Dogs.Contains (d) == false ) { Dogs.Add(d); d.AddBoss(this); } } public void RemoveDog( Dog d ) { if( d != null && Dogs.Contains(d) ) { Dogs.Remove (d); d.RemoveBoss(this); } } } 

通过这种方式,您可以在代码中对多对多进行建模,其中每只狗都知道他的老板,并且每个Boss都知道他的狗。 当您需要辅助表中的额外数据时,您还需要创建另一个类。

这是数据库之间的经典问题,其中多对多不起作用,因此您的帮助程序表,以及多对多工作正常的对象世界。 一旦关系具有属性,那么您应该创建一个新类来保存该信息。 但是,如果你看一下对象关系映射(ORM),那么你将节省很多时间,整个领域都是为了解决DB和Object之间的这个(以及许多其他)问题而长大的。

如果你有一个简单的多对多链接表,其中包含来自关系中每个表的外键,那么你可以按照你的建议对其进行建模:Boss有一个Dogs和Dog的集合有一个老板的集合。

如果您与额外数据(例如Nickname)存在多对多关系,那么您可以将其建模为两个一对多关系。 创建一个实体,例如DogBoss,以便Boss拥有DogBoss的集合,Dog拥有DogBoss的集合。

传统的多对多关系在匹配表上没有额外的字段。

因为你确实拥有具有独特信息的领域,所以我倾向于不再考虑这些关系。

一旦你向匹配表添加信息,我认为你已经把这个表本身变成了一个实体,所以需要它自己的对象来表示它。

此时,您可以开始使用DogsName类来连接人和狗 – 这两个类都包含对此对象的引用作为集合的一部分。

但是,你是否给狗一个名字来叫或拥有狗是独立的。

除了根据不同的人建模狗名称的关系,您还需要建立所有权关系的模型。 在内存中,这意味着两个对象都包含其他对象的列表。

如果您不需要记录昵称,那么Dog应该有一个老板列表,老板应该有一个狗列表。

如果Dog和Boss之间的关系具有属性,在这种情况下是昵称,那么你应该创建一个表示该关系的类,并让Dog和Boss都保存该类型的列表。

我已经使用NHibernate一段时间了,发现它对于缓解这种对象关系阻抗不匹配非常有用。

我想我错过了一些东西。 为什么许多人不允许?

 public class Boss { Dog[] dogs; } public class Dog { Boss[] bosses; } 

在关系模型中,模拟多对多关系的最佳方式(使用Dogs / Bosses的示例)是有三个单独的表。

一个用于DOGS的表,一个用于BOSSES的表(并且每个表具有唯一键),第三个表通常是“ 连接表 ”。

该表通常至少有两个字段,一个字段用于Dog的外键,另一个字段用于Boss的外键。 这样每条狗都可以拥有很多老板,每个老板可以拥有很多狗。

现在,当它以更面向对象的方式在代码中对其进行建模时,通常通过拥有Dog类和Boss类来实现。 除了为每个对象提供通常的primefaces属性外,每个对象还会公开一个属性,该属性是另一个对象的集合。

因此,例如,Dog对象将具有名为“Bosses”的属性。 此属性将公开分配给特定Dog对象的Boss对象集合(如联结表中所定义),另一方面,每个Boss对象将公开名为Dogs的属性,该属性将是已分配的Dog对象的集合到特定的Boss对象(由联结表定义)。

请注意,这些对象中可能存在一些“重叠”(即,一个“狗”对象可能具有另一个“狗”对象具有的“boss”对象),但是,这是用于翻译三个表的传统机制 – 将多个关系模型转化为面向对象的模型。

我错过了什么,或者是您需要的唯一代码,如下所示:

 List BossList; class Dog {} class Boss { Dog[] Dogs; } 

您不需要显式建模双向关系。 它隐含在代码结构中。 可能还有其他原因,但通常只有单向引用和遍历引用对象集的方法就足够了。

每当我们需要思考现实生活和我们的需求时。 在这种情况下,关键点是哪一个应该有另一个。

在现实生活中,狗和老板可能没有彼此。 但是您的软件需求应该影响这种关系。

  • 例如,如果您正在开发一个兽医患者管理软件,对于治疗流浪狗的兽医来说,患者(狗) – 监护人(老板)的关系应该是这样的:老板必须至少有一只狗和狗可能没有任何老板(然后老板id是这种关系的外键)这意味着在你的设计中,狗类必须拥有一组老板。 为什么,因为任何老板实例都不能在没有任何狗的情况下创建。 我们也可以使用数据逻辑来做出这个决定。 让我们考虑一下当你试图在数据库中保存你的狗和老板类时。 如果关系条件如上所述,在保存boss时应将联结记录插入联结表中。

  • 如果你正在开发一个不治疗流浪狗的兽医那个软件,那么患者 – 父母的关系必须是这样的:狗必须至少有一个老板,老板必须至少有一只狗,我们需要考虑这种特殊的关系案件。 这意味着如果没有彼此,就无法创建任何这些类实例。 所以我们需要在OO设计中定义这个专业。 这意味着我们需要一个代表这种依赖关系的类。 当然,这种依赖关系将存储在联结表中。

– 如果您的软件是为治疗流浪狗的兽医而开发的,而这些狗是由老板采用的,那么您的设计应该是这样的:任何狗都可能没有老板,任何老板可能在收养之前都没有任何狗。 在这种情况下,我们的OO设计需要关注这种特殊情况。 这种情况与第一种情况略有不同。 所以我们可以将任何类的集合添加到其他类中。 但是,任何这样的软件需求都会影响其他需求。 喜欢报道。 如果兽医对老板采用的狗的担忧,迟早他会问一个由谁采用哪条狗的报告。 就像在句子中一样,(老板采用的狗)如果狗类包含老板类的集合则更好。

我希望我能对你的问题给出正确的答案。

不确定你的要求。 但这是你想要的表结构:

狗桌

DOG_ID int PK DOG_Name varchar(50)

DogsPerBoss

ID int DOG_ID int BOSS_ID int DogNickName varchar(15)

老板

BOSS_ID int PK BOSS_Name varchar(50)