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

时间:2012-03-18 03:30:46

标签: c# oop object

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

  1. C#ASP.NET网络表单
  2. C#POCO业务对象
  3. 某种DAL ... SQL(如果我能搞清楚,可能是EF4)
  4. 我真的不想要一个让我的表示层直接与EF实体对话的响应。

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

    假设我创建了一个以某种方式管理的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
    

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

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

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

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

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

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

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

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

    因此,这引出了我最终的问题:

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

    正如我已经反思的那样......我得出结论,我需要创建表示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; }
    }
    

    反而会扩展为这样的东西:

    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?
    
        }
    }
    

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

    public static IEnumerable<Person> GetPeople()
    {
        ...
    }
    
    在我的BLL中

    可能会在每个用户添加到集合之前填充其数据吗?

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

3 个答案:

答案 0 :(得分:2)

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

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

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

(您也可以使用某种单独的Object Builder。)

无论何时更新某人,您都可以使用相关实体的ID更新所有支持信息。

UPDATE :像EF4这样的ORM功能非常强大,可以帮助您完成大量重复性任务(比如我所描述的映射)。重要的是保持您的架构灵活,并将持久性作为一个可交换层。看看here获得一些指导。此外,我发现“领域驱动设计”这本书对于理解这种分离以及如何为实体建模非常重要。

答案 1 :(得分:1)

我会将查找表镜像为枚举。然后,您将获得单个值中的id和名称。如果名称包含无法在标识符中使用的字符,则可以轻松创建属性以处理其他数据。

附加信息(例如示例代码,修改以适应,我在VB中编写,因此转换为C#将是nessecary):

Namespace Company.Data
  Public Enum EyeColor As Int16
    Unknown = 0
    Brown = 1
    Blue = 2
    Green = 3
  End Enum

  Public Enum HairColor As Int16
    Unknown = 0
    Brown = 1
    Blond = 2
    Red = 3
    Pink = 4
  End Enum
End Namespace



Public Class Person

  Public Property EyeColor As EyeColor = EyeColor.Unknown

  Public Property HairColor As HairColor = HairColor.Unknown

End Class

由于您使用枚举,因此各个枚举值将映射到数据库查找表键。因此,您可以使用aPersonObject.HairColor.ToString()获取展示广告,并且可以使用aPersonObject.HairColor

获取ID

您可以非常喜欢并使用一些代码生成(mabey T4模板)从数据库中的值自动创建您的枚举。

答案 2 :(得分:1)

您是否在EF中查看过“导航属性”?它允许您将ID保存在主类(即Person)中,并通过导航属性引用字符串属性。例如,您将拥有:

Person p = [从EF数据上下文获取记录]

p.state_id将引用状态的数字ID,而p.State.Name将是状态的字符串名称。 EF负责加载引用的状态记录。如果您使用数据库优先并定义了外键(有些工具可以将数据库优先转换为代码优先),它甚至可以自动为您创建它们。