C# 系列 Class 设计
C# Family Class Design
我正在为一个应用程序构建一个家庭单元 (class)。我已经做了一些搜索并找到了整个家谱的解决方案,但是这个应用程序不关心定义为 (Father, Mother, Child1, Child+ n)
此应用程序是关于 children(他们可以根据年龄和技能水平进行的活动),但需要参考 parents。 parents 仅用于报告目的,并且需要备案驾驶执照和保险。
正在使用 C# 和 EF Code First 构建应用程序。 None 的数据库注释元素已添加到 class 中,但这不是问题所在。
以下是我的 class。主要业务规则规定每个兄弟姐妹将有 his/her 自己的记录,但他们需要链接在一起,因此如果 parents 住在一起,则只发送一封邮件(电子或蜗牛)。如果parents离婚了,需要发两封信(或邮件)
public class Person
{
public int PersonId { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public string Suffix { get; set; }
public string Sex { get; set; }
public DateTime DOB { get; set; }
}
public class Youth : Person
{
public string CurrentGrade { get; set; }
public Adult Mother { get; set; }
public Adult Father { get; set; }
public Adult ICE { get; set; }
public virtual Adult Adult { get; set; }
}
public class Adult : Person
{
public string DriversLicense { get; set; }
public string StateIssued { get; set; }
public string AutoInsuranceCarrier { get; set; }
public string PolicyNumer { get; set; }
public string MaritalStatus { get; set; }
//foreign key
public int VehicleId { get; set; }
public virtual Vehicle Vehicle { get; set; }
}
public class Address
{
public int AddressId { get; set; }
public int PersonId { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string PostalCode { get; set; }
public virtual Person Person { get; set; }
}
我陷入的逻辑模式是兄弟姐妹将拥有相同的 AddressId。当我申请离婚的 parents 时失败了,每个人的地址都有一个 child。就邮寄而言,它会起作用,因为它们位于不同的地址。感觉不是最好的设计。如果这由 UI 处理,那么它将起作用。
我的下一个想法是创建一个家庭 class 并将每个家庭成员添加到其中。在这种情况下,用户必须选择哪些人住在哪个地址。
public class Family
{
public int FamilyId { get; set; }
public int AddressId { get; set; }
public List<Person> Person;
}
这似乎也不是最佳解决方案。我觉得有更好的设计。就是我自己找不到。
其中一种方法是否存在我尚未发现的缺陷?
有人可以指出我更好的方向吗?并解释为什么那个方向更好?
提前感谢您的所有见解!
"Father"、"Youth"、"Brother"等……不是人的属性,而是人与人之间关系的属性。一个人可以同时是"Father"和"Brother"和"Uncle"。
更好的设计是这样的(我不知道你的所有要求):
public class Person {
public Name{get;set;}
// etc...
public List<Relationship> Relationships{get;set;}
}
public class Relationship {
public Person P1{get;set;}
public Person P2{get;set;}
public RelationshipKind Kind{get;set;}
}
public class RelationshipKind {
// for example: Father
public Name1 {get;set;}
// for example: Child
public Name2 {get;set;}
}
通常您希望让您的模型像您想象的那样流畅。
例如,我不会有包含人物的地址 class。我将有一个地址 class 只包含有关地址的基本数据。亲自,我会有一个地址。这符合 "Person lives at this address" 并且可能会解决您的住所问题。这是 "Vehicle"
的设置类型
在不详细介绍整个设计的情况下,我将只关注地址问题。
我建议您将地址 class 定义为没有导航 属性 返回给某人的方式:
public class Address
{
public int AddressId { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string PostalCode { get; set; }
}
然后我会 link 你的 Adult
(甚至 Person
)class 到这样的地址:
public class Adult : Person
{
public string DriversLicense { get; set; }
public string StateIssued { get; set; }
public string AutoInsuranceCarrier { get; set; }
public string PolicyNumer { get; set; }
public string MaritalStatus { get; set; }
//foreign key
public int VehicleId { get; set; }
public virtual Vehicle Vehicle { get; set; }
public int AddressId {get; set;}
public virtual Address Address { get; set; }
}
使用这种方法,如果 parents 没有离婚,他们可以共享同一个地址实例。如果他们离婚了,您的申请必须为 parents 之一设置不同的地址。如果你需要找到住在同一地址的人,你可以这样做:
_dbContext.Persons.Where(p => p.AddressId = addressId) ...
如果您有 table 个州,那么您可以在很多地方使用它:DriversLicenseState、AddressState、InsuranceState 等。如果这不是空字符串,则您不必验证用户输入并可以在应用程序上放置 drop-down。
String 当前年级。如果您改为输入 child 进入一年级的年份,那么您不必每年手动更新它;它可以计算 - 尽管您还必须为 NumberOfYearsHeldBack 包含一个 int。但是,与每年更新每个学生相比,每隔一段时间更新一次 int 的工作量更少。
个人偏好:我喜欢 'NameLast' 和 'NameFirst' 而不是 'FirstName' 和 'LastName' 只是因为这意味着这些属性将在所有 IDE 下拉列表等,就像 AddressID、Address1 和 Address2
您可以考虑将 'Mother' 设为可为 null 的 'Mother?',将 'Father' 设为 'Father?' 也是如此。有些孩子根本没有两者 parents。如果你想在政治上正确,你可以考虑 'Parent1?' 和 'Parent2' 并枚举与 select 母亲、父亲、监护人的关系,因为有些孩子有 2 个妈妈或 2 个爸爸或他们的哥哥是他们的法定监护人。
在您的地址 class 中,为什么您已经有了 PersonID 属性 而还有一个人 属性?就此而言,为什么该地址根本没有 personID?这只需要 one-way。人有地址,地址没有人。这样你就可以让 5 个人都使用相同的地址。如果你试图让两者保持同步 two-way ,它就会出错,更不用说你必须在地址中有一个 personID 的 List<> 。由于地址是一种类型,因此为每个人添加另一个类型,这样您就有了 AddressPhysical 和 AddressMailing。现在你可以有 4 个孩子,每个孩子都有不同的睡觉地方,但他们都在奶奶家收到邮件 P.O.Box。
我不会在 child 中添加第三个成年人作为他们的 ICE。相反,我会制作一个成人列表<>(它实际上只是一个 ID 整数列表)这样你就可以在紧急情况下继续在列表中工作,直到你找到某人。
我正在为一个应用程序构建一个家庭单元 (class)。我已经做了一些搜索并找到了整个家谱的解决方案,但是这个应用程序不关心定义为 (Father, Mother, Child1, Child+ n)
此应用程序是关于 children(他们可以根据年龄和技能水平进行的活动),但需要参考 parents。 parents 仅用于报告目的,并且需要备案驾驶执照和保险。
正在使用 C# 和 EF Code First 构建应用程序。 None 的数据库注释元素已添加到 class 中,但这不是问题所在。
以下是我的 class。主要业务规则规定每个兄弟姐妹将有 his/her 自己的记录,但他们需要链接在一起,因此如果 parents 住在一起,则只发送一封邮件(电子或蜗牛)。如果parents离婚了,需要发两封信(或邮件)
public class Person
{
public int PersonId { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public string Suffix { get; set; }
public string Sex { get; set; }
public DateTime DOB { get; set; }
}
public class Youth : Person
{
public string CurrentGrade { get; set; }
public Adult Mother { get; set; }
public Adult Father { get; set; }
public Adult ICE { get; set; }
public virtual Adult Adult { get; set; }
}
public class Adult : Person
{
public string DriversLicense { get; set; }
public string StateIssued { get; set; }
public string AutoInsuranceCarrier { get; set; }
public string PolicyNumer { get; set; }
public string MaritalStatus { get; set; }
//foreign key
public int VehicleId { get; set; }
public virtual Vehicle Vehicle { get; set; }
}
public class Address
{
public int AddressId { get; set; }
public int PersonId { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string PostalCode { get; set; }
public virtual Person Person { get; set; }
}
我陷入的逻辑模式是兄弟姐妹将拥有相同的 AddressId。当我申请离婚的 parents 时失败了,每个人的地址都有一个 child。就邮寄而言,它会起作用,因为它们位于不同的地址。感觉不是最好的设计。如果这由 UI 处理,那么它将起作用。
我的下一个想法是创建一个家庭 class 并将每个家庭成员添加到其中。在这种情况下,用户必须选择哪些人住在哪个地址。
public class Family
{
public int FamilyId { get; set; }
public int AddressId { get; set; }
public List<Person> Person;
}
这似乎也不是最佳解决方案。我觉得有更好的设计。就是我自己找不到。
其中一种方法是否存在我尚未发现的缺陷? 有人可以指出我更好的方向吗?并解释为什么那个方向更好?
提前感谢您的所有见解!
"Father"、"Youth"、"Brother"等……不是人的属性,而是人与人之间关系的属性。一个人可以同时是"Father"和"Brother"和"Uncle"。
更好的设计是这样的(我不知道你的所有要求):
public class Person {
public Name{get;set;}
// etc...
public List<Relationship> Relationships{get;set;}
}
public class Relationship {
public Person P1{get;set;}
public Person P2{get;set;}
public RelationshipKind Kind{get;set;}
}
public class RelationshipKind {
// for example: Father
public Name1 {get;set;}
// for example: Child
public Name2 {get;set;}
}
通常您希望让您的模型像您想象的那样流畅。
例如,我不会有包含人物的地址 class。我将有一个地址 class 只包含有关地址的基本数据。亲自,我会有一个地址。这符合 "Person lives at this address" 并且可能会解决您的住所问题。这是 "Vehicle"
的设置类型在不详细介绍整个设计的情况下,我将只关注地址问题。
我建议您将地址 class 定义为没有导航 属性 返回给某人的方式:
public class Address
{
public int AddressId { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string PostalCode { get; set; }
}
然后我会 link 你的 Adult
(甚至 Person
)class 到这样的地址:
public class Adult : Person
{
public string DriversLicense { get; set; }
public string StateIssued { get; set; }
public string AutoInsuranceCarrier { get; set; }
public string PolicyNumer { get; set; }
public string MaritalStatus { get; set; }
//foreign key
public int VehicleId { get; set; }
public virtual Vehicle Vehicle { get; set; }
public int AddressId {get; set;}
public virtual Address Address { get; set; }
}
使用这种方法,如果 parents 没有离婚,他们可以共享同一个地址实例。如果他们离婚了,您的申请必须为 parents 之一设置不同的地址。如果你需要找到住在同一地址的人,你可以这样做:
_dbContext.Persons.Where(p => p.AddressId = addressId) ...
如果您有 table 个州,那么您可以在很多地方使用它:DriversLicenseState、AddressState、InsuranceState 等。如果这不是空字符串,则您不必验证用户输入并可以在应用程序上放置 drop-down。
String 当前年级。如果您改为输入 child 进入一年级的年份,那么您不必每年手动更新它;它可以计算 - 尽管您还必须为 NumberOfYearsHeldBack 包含一个 int。但是,与每年更新每个学生相比,每隔一段时间更新一次 int 的工作量更少。
个人偏好:我喜欢 'NameLast' 和 'NameFirst' 而不是 'FirstName' 和 'LastName' 只是因为这意味着这些属性将在所有 IDE 下拉列表等,就像 AddressID、Address1 和 Address2
您可以考虑将 'Mother' 设为可为 null 的 'Mother?',将 'Father' 设为 'Father?' 也是如此。有些孩子根本没有两者 parents。如果你想在政治上正确,你可以考虑 'Parent1?' 和 'Parent2' 并枚举与 select 母亲、父亲、监护人的关系,因为有些孩子有 2 个妈妈或 2 个爸爸或他们的哥哥是他们的法定监护人。
在您的地址 class 中,为什么您已经有了 PersonID 属性 而还有一个人 属性?就此而言,为什么该地址根本没有 personID?这只需要 one-way。人有地址,地址没有人。这样你就可以让 5 个人都使用相同的地址。如果你试图让两者保持同步 two-way ,它就会出错,更不用说你必须在地址中有一个 personID 的 List<> 。由于地址是一种类型,因此为每个人添加另一个类型,这样您就有了 AddressPhysical 和 AddressMailing。现在你可以有 4 个孩子,每个孩子都有不同的睡觉地方,但他们都在奶奶家收到邮件 P.O.Box。
我不会在 child 中添加第三个成年人作为他们的 ICE。相反,我会制作一个成人列表<>(它实际上只是一个 ID 整数列表)这样你就可以在紧急情况下继续在列表中工作,直到你找到某人。