如何设计包含查找表属性的类?

oct*_*ist 6 c# oop object

一些上下文:这与我开始构建多层Web应用程序的愿望有关:

  1. C#ASP.NET Web表单
  2. C#POCO业务对象
  3. 某种DAL ... SQL(或者EF4,如果我能算出来的话)

例如,我真的不想要一个让我的表示层直接与EF实体对话的响应.

我用C#ASP.NET和SQL做了自己的Web开发已有10年了,但在正式的OOAD方面,我仍然是新手.我最近一直热衷于追求这种技能,但我仍然很擅长并且有些东西我无法完全理解.我希望有人能以一种带来顿悟的方式来解释它:

假设我创建了一个以某种方式管理People的Web应用程序,我的Person对象必须拥有FirstName,LastName,HairColor,EyeColor,Ethnicity,StateOrProvince等属性.我正在使用SQL Server进行持久性...所以常识会指示People表中的相应字段都是外键:

FirstName varchar(50)
LastName varchar(50)
HairColor tinyint
EyeColor tinyint
Ethnicity tinyint
StateOrProvince tinyint
Run Code Online (Sandbox Code Playgroud)

显然,这意味着我为每个字段(即HairColors表,EyeColors表,种族表等)都有相应的查找表,并且每个查找表都有一个ID和一个名称.当然,每当我想显示有关Person的任何有用信息时,这些查找表中的Name字段将与我的People数据一起加入.

该网站的一些主要功能将是:

1.)在Gridview中枚举人物(FirstName,LastName,HairColor,EyeColor,Ethnicity,StateOrProvince)

2.)在只读页面上显示个人的详细信息(FirstName,LastName,HairColor,EyeColor,Ethnicity,StateOrProvince)

3.)允许用户在更新页面上更新单个Person的数据(FirstName,LastName,HairColor,EyeColor,Ethnicity,StateOrProvince)

案例#1 如果我在网格视图中枚举Person对象的集合...每个Person实例都需要将其HairColor,EyeColor,Ethnicity,StateOrProvince属性显示有意义的字符串(即SQL查找表中的Name字段,不是它的ID).很明显,我的SQL sproc会有一些JOIN来为我提供在每个Person实例中填充这些文本属性所需的相应字符串数据.

情况#2 再次,我的sproc将有一个JOIN将人类可读的属性名称作为字符串返回,我将使用myPerson.HairColor,myPerson.EyeColor等内容在只读Label控件中显示它们.

案例#3 在这里,我将显示一个页面,其中包含每个属性的下拉列表(即value = HairColorId,Text = HairColorName).我在这里的直接本能是使用每个属性的ID(类似于myPerson.HairColorId)来遍历DDL项并选择一个值,该值表示People表当前为此Person保留的头发颜色.如果用户在任何属性DDL中选择了不同的东西,我需要将相应的SelectedId值传递给UPDATE sproc,并修改People表中针对此特定Person的值.

所以这引出了我最终的问题:

我如何最好地设计一个Person对象,使其包含HairColor,EyeColor,Ethnicity,StateOrProvince的ID和Name,以便我可以在显示信息时使用Name,但初始化更新DDL控件的ID ...最终处理更新

正如我已经反思的那样......我得出的结论是,我需要创建表示HairColor,EyeColor,Ethnicity,StateOrProvince属性的类.

然后是我的Person类,而不是像这样:

public class Person
{
    string FirstName { get; set; }
    string LastName { get; set; }

    int HairColorId { get; set; }
    string HairColorName { get; set; }

    int EyeColorId { get; set; }
    string EyeColorName { get; set; }

    int StateOrProvinceId { get; set; }
    string StateOrProvinceName { get; set; }
    string StateOrProvinceCode { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

相反,将扩展为这样的东西:

public class HairColor
{
    int Id { get; set; }
    string Name { get; set; }
}

public class EyeColor
{
    int Id { get; set; }
    string Name { get; set; }
}

public class StateOrProvince
{
    int Id { get; set; }
    string Name { get; set; }
    string Code { get; set; }
}

public class Person
{
    HairColor HairColor { get; set; }
    EyeColor EyeColor { get; set; }
    StateOrProvince StateOrProvince { get; set; }

    public Person()
    {
        // how do I initialize a Person from a SQL data row?

    }
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我的Person类看起来像上面那样......我究竟如何从SQL查询返回的给定数据行中最好地初始化它(无论是单独还是集合)?我似乎记得我不应该在构造函数中新建东西(即this.HairColor = new HairColor(dr ["HairColorId"),dr ["HairColorName"];)...所以我想知道如何拨电至

public static IEnumerable<Person> GetPeople()
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

在我的BLL中,可能会在将每个用户添加到集合之前将其数据填满?

真的希望有人能在这里给我一个"哈哈"的时刻......

Jor*_*dão 2

我认为你有正确的方法,为那些支持实体创建类(尽管我会放入StateOrProvince一个单独的Address实体,也许所有这些特征都放在一个单独的PersonTraits实体中)。

有很多方法可以解决这个问题。如果没有 ORM,请查看数据映射器(也可参见Dependent Mapping),它可用于从数据库查询映射到实例Person。这是映射器代码的概述:

var row = ... // query database
var person = new Person(row["FirstName"], row["LastName"]);
person.EyeColor = new EyeColor(row["EyeColorID"], row["EyeColorName"]);
...
Run Code Online (Sandbox Code Playgroud)

(您还可以使用某种单独的对象生成器。)

每当您更新某人时,您都会更新所有支持信息以及使用相关实体的 ID。

更新:像 EF4 这样的 ORM 非常强大,可以帮助您完成许多重复性任务(如我描述的映射)。重要的是保持架构的灵活性,并作为一个可交换层具有持久性。请查看此处以获取一些指导。另外,我发现“领域驱动设计”这本书对于理解这种分离以及如何对实体进行建模非常重要。