Как мне разработать класс, содержащий свойства из справочных таблиц? - PullRequest
6 голосов
/ 18 марта 2012

Некоторый контекст: это относится к моему растущему желанию создавать многослойные веб-приложения с:

  1. C # ASP.NET веб-формами
  2. C # POCO бизнес-объектами
  3. Какой-то DAL ... SQL (или, может быть, EF4, если я смогу это выяснить)

Я бы не очень хотел получить ответ с моим уровнем представлениянапример, напрямую общаясь с сущностями EF.

Я занимаюсь веб-разработкой на C # ASP.NET & SQL уже 10 лет, но я все еще новичок, когда дело доходит до формального OOAD,В последнее время я увлекаюсь этим навыком со страстью, но я все еще новичок в этом, и есть кое-что, что я не могу обернуть вокруг себя.Я надеюсь, что кто-то может объяснить это так, что это приведет к прозрению:

Допустим, я создаю веб-приложение, которое каким-то образом управляет People , и мой объект 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, таблица Ethnicities и т. Д.), И каждая из этих таблиц поиска имеет идентификатор и имя.Конечно, поле «Имя» в этих таблицах поиска будет объединено с моими данными «Люди» всякий раз, когда я хочу показать что-либо полезное о персоне.

Некоторые ключевые функции сайта:

1.) Перечисление людей в сетке (Имя, Фамилия, Цвет волос, Цвет глаз, Этническая принадлежность, StateOrProvince)

2.) Отображение сведений об отдельном лице только для чтениястраница (FirstName, LastName, HairColor, EyeColor, Ethnicity, StateOrProvince)

3.) Разрешить пользователю обновлять данные отдельного лица на странице обновления (FirstName, LastName, HairColor, EyeColor, Ethnicity, StateOrProvince)

Case # 1 Если бы я перечислял коллекцию объектов Person в виде сетки ... каждый экземпляр Person должен был бы отображать свой HairColor, EyeColor, Ethnicity, StateOrProvinceсвойства как строки должны быть значимыми (т. е. поле Имя из справочной таблицы SQL, а не его идентификатор).Ясно, что у моего SQL sproc было бы несколько JOIN, чтобы дать мне соответствующие строковые данные, которые мне нужны для заполнения этих текстовых свойств в каждом экземпляре Person.

Case # 2 И снова у моего sproc будет JOIN toвернуть имена читаемых человеком свойств в виде строк , и я бы отобразил их в элементах управления Label только для чтения, используя что-то вроде myPerson.HairColor, myPerson.EyeColor и т. д.

Case #3 Здесь я буду показывать страницу с выпадающими списками для каждого из этих свойств (то есть value = HairColorId, Text = HairColorName).Моим непосредственным инстинктом здесь было бы использовать идентификаторы каждого свойства (что-то вроде myPerson.HairColorId) для циклического перемещения по элементам DDL и выбора значения, представляющего цвет волос, для которого в настоящее время хранится таблица People.этот человек.Если пользователь выберет что-то другое в каком-либо из DDL свойств, мне нужно будет передать соответствующие значения SelectedId в строку UPDATE и изменить значения в таблице People для этого конкретного Person.

Так что это приводитОтвет на главный вопрос:

Как лучше всего спроектировать объект Person таким образом, чтобы он содержал как идентификатор, так и имя для HairColor, EyeColor, Ethnicity, StateOrProvince, чтобы впоследствии я мог использовать Имя когда отображает информацию, но идентификатор для инициализации обновлений элементов управления 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 ]

2 голосов
/ 18 марта 2012

Я думаю, что у вас правильный подход, создавая классы для этих вспомогательных сущностей (хотя я бы поместил 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"]);
...

(Вы также можете использовать какой-то отдельный Строитель объектов .)

Каждый раз, когда вы обновляете человека, выобновите всю вспомогательную информацию, используя идентификатор связанных сущностей.

ОБНОВЛЕНИЕ : ORM, такой как EF4, очень мощный и поможет вам в выполнении множества повторяющихся задач (таких как отображение Iописал).Важно, чтобы ваша архитектура была гибкой и имела постоянство как один сменный слой.Взгляните здесь для некоторых указаний.Кроме того, я обнаружил, что книга «Проектирование на основе доменов» действительно важна для понимания такого разделения и того, как моделировать ваши сущности.

1 голос
/ 19 марта 2012

Вы смотрели на "свойство навигации" в EF?Это позволит вам хранить идентификаторы в главном классе (т.е. Person) и ссылаться на свойства строки через свойства навигации.Например, у вас будет:

Person p = [получить запись из контекста данных EF]

p.state_id будет ссылаться на числовой идентификатор состояния, тогда как p.State.Name будетбыть строковым именем штата.EF заботится о загрузке указанной записи состояния.Он может даже создавать их для вас автоматически, если вы используете базу данных сначала и у вас определены внешние ключи (есть инструменты, которые преобразуют базу данных сначала в код сначала)

1 голос
/ 18 марта 2012

Я бы зеркалировал ваши таблицы поиска как перечисления. Затем вы получите и идентификатор и имя в одном значении. Если имена включают символы, которые нельзя использовать в идентификаторе, вы можете легко создать атрибут для обработки дополнительных данных.

Дополнительная информация (например, пример кода, изменить, чтобы удовлетворить, я пишу на VB, поэтому преобразование в C # будет необязательно):

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

Вы можете по-настоящему полюбить и использовать несколько кодов поколения (шаблоны mabey T4) для автоматического создания ваших перечислений из значений в базе данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...