假设我在数据库中有2个表。 例如:Dog&老板 这是一个多对多的关系,导致一个老板可以拥有超过1只狗,而一只狗可以拥有超过1个主人。我是鲍比的老板,但我的妻子也是。
但是不允许多对多,所以有一个很好的帮助:DogsPerBoss
如何在代码中对此进行建模?
Class Boss可以拥有一系列Dogs。 Class Dog可以拥有一系列老板。 - >至少,这就是我的想法。也许有更好的解决方案?
辅助表中的额外数据怎么样? 应该是de Boss级还是Dog级? 例如:昵称 (我把狗称为“好男孩”,我的妻子称他为“小狗”)
我希望我的问题有点清楚吗? 有什么最好的方法来实现这个目标是什么? 你能给我一些参考资料吗?
ORM(如NHibernate)不是一个选项。
答案 0 :(得分:22)
你为什么要谈论桌子?您在创建对象模型还是数据库模型?
对于对象模型,狗没有理由不能拥有List<Owner>
且拥有者拥有List<Dog>
。只有在关系上有属性时才需要中间类(UML称为关联类)。当你有一个具有额外属性的DogOwnership类时,每个所有者都会有一个List<DogOwnership>
,每个Dog都会这样。 DogOwner会有一只狗,一个主人和额外的财产。
答案 1 :(得分:13)
public class Boss
{
private string name;
private List<Hashtable> dogs;
private int limit;
public Boss(string name, int dogLimit)
{
this.name = name;
this.dogs = new List<Hashtable>();
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<Boss> bosses;
public Dog(string name)
{
this.name = name;
this.bosses = new List<Boss>();
}
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<Boss> Bosses { get { return new ReadOnlyCollection<Boss>(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.
你可以在你认为合适的情况下调整它,但是,我认为你所寻找的基本原理是存在的。
答案 2 :(得分:5)
像这样的东西; 它仍然需要一些微调(将集合设为私有并为其添加一个只读的公共访问器,例如返回readonlycollection,但你会发现漂移。
public class Dog
{
public List<Boss> 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<Dog> 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都知道他的狗。 当您需要辅助表中的额外数据时,您还需要创建另一个类。
答案 3 :(得分:1)
如果您不需要记录昵称,那么Dog应该有一份老板名单,Boss应该有一份狗名单。
如果Dog和Boss之间的关系具有属性,在这种情况下是昵称,那么你应该创建一个表示该关系的类,并让Dog和Boss都保存该类型的列表。
我一直在使用NHibernate一段时间,发现它对于缓解此类object relational impedance mismatch非常有用。
答案 4 :(得分:1)
这是数据库之间的经典问题,其中多对多不起作用,因此您的帮助程序表,以及多对多工作正常的对象世界。一旦关系具有属性,那么您应该创建一个新类来保存该信息。但是,如果你看一下对象关系映射 - ORM,那么你将节省很多时间,整个领域都是为了解决DB和Object之间的这个(以及许多其他)问题。
答案 5 :(得分:1)
如果你有一个简单的多对多链接表,其中包含来自关系中每个表的外键,那么你可以按照你的建议对其进行建模:Boss有一系列Dogs and Dog有一个老板的集合。
如果您与额外数据(如昵称)有多对多关系,那么您可以将其建模为两个一对多关系。创建一个实体,例如DogBoss,以便Boss拥有DogBoss的集合,Dog拥有DogBoss的集合。
答案 6 :(得分:1)
传统的多对多关系在匹配表上没有额外的字段。
因为你确实拥有具有独特信息的字段,所以我倾向于不再考虑这些关系。
一旦你将信息添加到匹配表中,我认为你已经将这个表本身变成了一个实体,因此需要它自己的对象来代表它。
此时,您可以开始使用DogsName类来连接人和狗 - 这两个类都将包含对此对象的引用作为集合的一部分。
然而,你是否给狗一个名字叫狗或拥有狗是独立的。
除了根据不同的人建模狗名称的关系之外,您还需要对所有权关系进行建模。在内存中,这意味着两个对象都包含其他对象的列表。
答案 7 :(得分:0)
我想我错过了什么。为什么许多人不允许?
public class Boss
{
Dog[] dogs;
}
public class Dog
{
Boss[] bosses;
}
答案 8 :(得分:0)
在关系模型中,模拟多对多关系的最佳方式(使用你的狗/老板的例子)是有三个单独的表。
一个DOGS表,一个BOSSES表(每个表都有一个唯一键),第三个表通常是“junction table”。
这个表通常至少有两个字段,一个字段用于Dog的外键,另一个字段用于Boss的外键。 这样每只狗都可以拥有很多老板,每个老板都可以拥有很多狗。
现在,当它以更面向对象的方式在代码中对其进行建模时,通常通过使用Dog类和Boss类来实现。 除了为每个这些对象提供通常的原子属性外,每个对象都有 还暴露了另一个属性的属性。
因此,例如,Dog对象将具有名为“Bosses”的属性。此属性将公开分配给特定Dog对象的Boss对象集合(如联结表中所定义),另一方面,每个Boss对象将公开名为Dogs的属性,该属性将是已分配的Dog对象的集合到特定的Boss对象(由联结表定义)。
请注意,这些对象中可能存在一些“重叠”(即一个“狗”对象可能具有另一个“狗”对象具有的“boss”对象),但是,这是翻译三个对象的传统机制。将多对多关系模型表格化为面向对象的模型。
答案 9 :(得分:0)
我是否遗漏了某些内容,或者是您需要的唯一代码,如下所示:
List<Bosses> BossList;
class Dog {}
class Boss { Dog[] Dogs; }
您无需明确建模双向关系。它隐含在代码结构中。可能还有其他原因,但一般情况下,单向引用和遍历引用对象集的方法就足够了。
答案 10 :(得分:0)
每当我们需要思考现实生活和我们的需求时。在这种情况下,关键点是哪一个应该有另一个。
在现实生活中,狗和老板可能没有彼此。但是你的软件需求应该影响这种关系。
例如,如果您正在开发一个兽医患者管理软件,对于治疗流浪狗的兽医来说,患者(狗) - 监护人(老板)的关系应该是这样的: 老板必须至少有一只狗和狗可能没有任何老板(然后boss id是这种关系的外键),这意味着在你的设计中,狗类必须拥有一组老板。为什么因为没有任何狗都无法创建任何boss实例。我们也可以使用数据逻辑来做出这个决定。让我们考虑一下您何时尝试将您的狗和老板课程保存在数据库中。如果上述关系条件,在保存boss时应将联结记录插入联结表中。
如果你正在开发一个不治疗流浪狗的兽医那个软件,那么患者 - 父母的关系必须是这样的: 一只狗必须至少有一个老板,老板必须至少有一只狗,我们需要考虑这种特殊情况。这意味着如果没有彼此,就无法创建任何这些类实例。所以我们需要在OO设计中定义这个特性。这意味着我们需要一个代表这种依赖关系的类。当然,这种依赖关系将存储在联结表中。
- 如果您的软件是为治疗流浪狗的兽医开发的,而这些狗是由老板采用的,那么您的设计应该是这样的: 任何狗可能没有老板,任何老板可能没有任何狗,直到收养。在这种情况下,我们的OO设计需要关注这种特殊情况。这种情况与第一种情况略有不同。所以我们可以将任何类的集合添加到其他类中。但是,任何像这样的软件需求都会影响其他需求。喜欢报道。如果兽医对老板采用的狗的担忧,迟早他会问一个由谁采纳的狗的报告。就像句子一样,(老板采用的狗)如果狗类包含一系列老板类,那就更好了。
我希望我能对你的问题给出正确答案。
答案 11 :(得分:-1)
不确定你要求的是什么。但这是你想要的表结构:
DOG_ID int PK DOG_Name varchar(50)
ID int DOG_ID int BOSS_ID int DogNickName varchar(15)
BOSS_ID int PK BOSS_Name varchar(50)