我第一次在这个网站上,所以如果标签错误或在其他地方被回答了,我深表歉意…
我在目前的项目中不断遇到特殊的情况,我想知道你们会如何处理它。模式是:一个具有子级集合的父级,并且该父级具有对子集合中特定项的一个或多个引用,通常是“默认”子级。
一个更具体的例子:
public class SystemMenu
{
public IList<MenuItem> Items { get; private set; }
public MenuItem DefaultItem { get; set; }
}
public class MenuItem
{
public SystemMenu Parent { get; set; }
public string Name { get; set; }
}对我来说,这似乎是一种很好的清晰的关系建模方式,但由于循环关联,我无法在DB中强制执行关系,并且LINQ To SQL由于循环关联而崩溃。即使我可以绕过这个问题,这显然也不是一个好主意。
我目前唯一的想法是在MenuItem上有一个'IsDefault‘标志:
public class SystemMenu
{
public IList<MenuItem> Items { get; private set; }
public MenuItem DefaultItem
{
get
{
return Items.Single(x => x.IsDefault);
}
set
{
DefaultItem.IsDefault = false;
value.DefaultItem = true;
}
}
}
public class MenuItem
{
public SystemMenu Parent { get; set; }
public string Name { get; set; }
public bool IsDefault { get; set; }
}有没有人处理过类似的事情,并能提供一些建议?
干杯!
编辑:感谢到目前为止的回复,也许“菜单”的例子并不出色,但我正在努力想出一些有代表性的东西,这样我就不必进入我们不是很清楚的领域模型的细节了!也许一个更好的例子是公司/员工关系:
public class Company
{
public string Name { get; set; }
public IList<Employee> Employees { get; private set; }
public Employee ContactPerson { get; set; }
}
public class Employee
{
public Company EmployedBy { get; set; }
public string FullName { get; set; }
}员工肯定需要引用他们的公司,而且每个公司只能有一个ContactPerson。希望这能让我的观点更清晰一点!
发布于 2009-03-09 14:15:54
感谢所有回答的人,一些非常有趣的方法!最后,我不得不匆忙地完成了一些事情,所以我想出了这个想法:
引入了名为WellKnownContact的第三个实体和相应的WellKnownContactType枚举:
public class Company
{
public string Name { get; set; }
public IList<Employee> Employees { get; private set; }
private IList<WellKnownEmployee> WellKnownEmployees { get; private set; }
public Employee ContactPerson
{
get
{
return WellKnownEmployees.SingleOrDefault(x => x.Type == WellKnownEmployeeType.ContactPerson);
}
set
{
if (ContactPerson != null)
{
// Remove existing WellKnownContact of type ContactPerson
}
// Add new WellKnownContact of type ContactPerson
}
}
}
public class Employee
{
public Company EmployedBy { get; set; }
public string FullName { get; set; }
}
public class WellKnownEmployee
{
public Company Company { get; set; }
public Employee Employee { get; set; }
public WellKnownEmployeeType Type { get; set; }
}
public enum WellKnownEmployeeType
{
Uninitialised,
ContactPerson
}它感觉有点麻烦,但绕过了循环引用的问题,并且干净地映射到DB上,这样就省去了试图让LINQ to SQL做任何太聪明的事情!还允许多种类型的“知名联系人”,这肯定会在下一个sprint中出现(所以不是真正的YAGNI!)。
有趣的是,一旦我提出了人为的Company/Employee示例,与我们真正处理的相当抽象的实体相比,它使思考变得更加容易。
发布于 2009-03-07 17:16:31
解决这个问题的诀窍是意识到父母不需要知道孩子的所有方法,孩子也不需要知道父母的所有方法。因此,您可以使用Interface Segregation Principle将它们解耦。
简而言之,您为父对象创建了一个接口,该接口只包含子对象所需的那些方法。您还可以为子对象创建一个接口,该接口只包含父对象所需的那些方法。然后让父接口包含子接口的列表,并且让子接口指向父接口。我称其为Flip Flob模式,因为UML图具有Eckles-Jordan触发器的几何形状(Sue me,我是一个老硬件工程师!)
|ISystemMenu|<-+ +->|IMenuItem|
A 1 \ / * A
| \/ |
| /\ |
| / \ |
| / \ |
| / \ |
|SystemMenu| |MenuItem|请注意,此图中没有循环。您不能从一个类开始,然后沿着箭头回到您的起点。
有时,为了得到正确的分离,你必须移动一些方法。可能有一些你认为应该放在SystemMenu中的代码被转移到了MenuItem中,等等。但总的来说,这项技术运行得很好。
发布于 2009-03-05 18:42:58
你的解决方案看起来很合理。
另一件需要考虑的事情是,内存中的对象不必与数据库模式完全匹配。在数据库中,您可以使用具有子属性的更简单的模式,但在内存中,您可以进行优化,并使父对象具有对子对象的引用。
https://stackoverflow.com/questions/615968
复制相似问题