2012-03-18 9 views
6

un poco de contexto: Esto se refiere a mi deseo ciernes para construir aplicaciones web con múltiples capas: forma¿Cómo diseño una clase que contenga propiedades de tablas de búsqueda?

  1. C# ASP.NET Web
  2. negocio
  3. C# objetos POCO
  4. Algún tipo de DAL ... SQL (o tal vez EF4 si puedo averiguarlo)

realmente no lo desee una respuesta que tiene mi capa de presentación hablando directamente a las entidades de EF, por ejemplo.

He estado haciendo mi propio desarrollo web con C# ASP.NET & SQL durante 10 años, pero todavía soy un novato total cuando se trata de OOAD formal. He estado siguiendo esta habilidad con pasión últimamente, pero todavía soy nuevo en eso y hay algo que no puedo entender. Estoy esperando que alguien puede explicarlo de una manera que trae una epifanía:

Digamos que puedo crear una aplicación web que gestiona personas de alguna manera, y mi objeto persona debe poseer unas propiedades tales como Nombre, Apellido, Color de pelo, color de ojos, Etnia, StateOrProvince, etc. estoy usando SQL Server para la persistencia ... así que el sentido común dictaría que los respectivos campos de la tabla las personas son todas las claves externas:

FirstName varchar(50) 
LastName varchar(50) 
HairColor tinyint 
EyeColor tinyint 
Ethnicity tinyint 
StateOrProvince tinyint 

es evidente que esto significa que Tengo tablas de búsqueda correspondientes para cada uno de esos campos (es decir, la tabla HairColors, la tabla EyeColors, la tabla Ethnicities, etc.) y cada una de estas tablas de búsqueda tiene un ID y un nam mi. Por supuesto, el campo Nombre en estas tablas de búsqueda se UNIRÁ con mis datos de Gente cuando quiera mostrar algo útil sobre una Persona.

Algunas de las características clave del sitio sería:

1.) personas Enumerar en un Gridview (Nombre, Apellido, color de cabello, color de ojos, el origen étnico, StateOrProvince)

2.) Mostrar detalles de una persona individual en una página de sólo lectura (Nombre, Apellido, color de cabello, color de ojos, etnia, StateOrProvince)

3.) permitir a un usuario actualizar los datos de una persona individual en una página de actualización (Nombre, Apellido, color de cabello, color de ojos, Etnia, StateOrProvince)

Caso # 1 Si yo estaba enumerando una colección de objetos persona en un gridview ... cada instancia de persona tendría que mostrar su Las propiedades de HairColor, EyeColor, Ethnicity, StateOrProvince como cadenas tienen significado (es decir, el campo Nombre de la tabla de búsqueda de SQL, no su ID). Claramente mi sproc de SQL tendría algunos JOINs para darme los datos de cadena apropiados que necesito para completar estas propiedades de texto en cada instancia de Person.

Caso # 2 nuevo mi sproc tendría un JOIN para recuperar los nombres de las propiedades legibles como cadenas, y me los muestra en sólo controles Label leer usando algo como myPerson.HairColor, myPerson.EyeColor , etc.

Caso # 3 Aquí estaría mostrando una página con listas desplegables para cada una de estas propiedades (es decir, valor = HairColorId, Text = HairColorName). Mi instinto inmediato sería usar las identificaciones de cada propiedad (algo así como myPerson.HairColorId) para recorrer los elementos DDL y seleccionar un valor que represente el color de cabello que la tabla Personas tiene actualmente para esta Persona. Si el usuario seleccionó algo diferente en cualquiera de los DDL de la propiedad, necesitaría pasar los valores apropiados de SelectedId a un sproc de ACTUALIZACIÓN, y modificar los valores en la tabla de Personas para esta Persona en particular.

Así que me lleva a la última pregunta:

¿Cómo mejor diseño de un objeto Person de forma que contenga tanto el identificador y el nombre de color de cabello, color de ojos, Etnia, StateOrProvince así que puede posteriormente utilizar el nombre cuando muestra información, pero ID para inicializar la actualización Controles DDL ... y en última instancia procesamiento actualizaciones?

Como he reflexionado sobre esto ... he llegado a la conclusión de que necesito crear clases para representar las propiedades HairColor, EyeColor, Ethnicity, StateOrProvince.

Entonces mi clase de persona, en lugar de ser algo como esto:

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

En vez de ello se ampliará en algo como esto:

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? 

    } 
} 

Pero entonces, si mi clase de persona se parece a los anteriores ... ¿cómo diablos puedo inicializarlo (ya sea individualmente o en una colección) a partir de una fila dada de datos que obtengo de una consulta SQL? Me parece recordar que no debería estar renovando cosas en un constructor (es decir, this.HairColor = new HairColor (dr ["HairColorId"), dr ["HairColorName"];) ... así que me pregunto cómo llamar a

public static IEnumerable<Person> GetPeople() 
{ 
    ... 
} 

en mi BLL podría llenar a cada usuario con sus datos antes de que se agregue a la colección?

realmente esperando que alguien me puede dar un momento "a-ha" aquí ...

Respuesta

2

Creo que tiene el enfoque correcto, la creación de clases para aquellas entidades de apoyo (aunque me gustaría poner en un StateOrProvinceAddress entidad separada, y tal vez todos esos rasgos en una entidad separada PersonTraits).

Hay muchas formas de solucionar esto. Sin un ORM, eche un vistazo a Data Mappers (también en Dependent Mapping), que podría usarse para mapear desde una consulta de base de datos a una instancia de Person. Este es un resumen del código asignador: (. También es posible usar algún tipo de separada Object Builder)

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

Cada vez que se actualiza una persona, actualizar toda la información complementaria, así utilizando el ID de la entidades relacionadas.

ACTUALIZACIÓN: un ORM como EF4 es muy potente y lo ayudaría con muchas tareas repetitivas (como el mapeo que he descrito). Lo importante es mantener su arquitectura flexible y tener persistencia como una sola capa intercambiable. Eche un vistazo here para alguna orientación. Además, descubrí que el libro "Diseño impulsado por el dominio" es realmente importante para comprender este tipo de separación y cómo modelar sus entidades.

+0

Gracias. Encapsular StateOrProvince en una clase de dirección es correcto en el dinero.Creo que ese hubiera sido mi próximo paso lógico una vez que comencé a construir esto. Sin embargo, nunca pensé dar un paso más con "PersonTraits" porque está muy lejos del esquema DB. Supongo que estoy demasiado acostumbrado a pensar en términos de mi modelo SQL que no puedo liberar mi mente para pensar en un modelo de objetos. – octechnologist

+0

¿Sugeriría que use un ORM? Me metí con EF4 como DAL en un sitio de prueba anterior hace aproximadamente 6 meses ... pero no creo que estuviera mentalmente preparado para eso. Estoy llegando a un punto con mi comprensión de OOP que podría tener más sentido para mí ahora. – octechnologist

+1

Claro, un ORM como EF4 es muy poderoso y te ayudaría con muchas tareas repetitivas (como el mapeo que he descrito). Lo importante es mantener su arquitectura flexible y tener persistencia como una sola capa intercambiable. Eche un vistazo [aquí] (http://blogs.msdn.com/b/adonet/archive/2009/05/21/poco-in-the-entity-framework-part-1-the-experience.aspx) para alguna orientación. Además, descubrí que el libro "Diseño impulsado por el dominio" es realmente importante para comprender este tipo de separación y cómo modelar sus entidades. –

1

Me reflejar sus tablas de búsqueda como enumeraciones. Luego obtienes tanto la identificación como el nombre en un solo valor. Si los nombres incluyen caracteres que no se pueden usar en un identificador, entonces puede crear fácilmente un atributo para manejar los datos adicionales.

Información adicional (por ejemplo Código de ejemplo, modificar para adaptarse, escribo en VB lo que la conversión a C# será 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 

dado que está utilizando enumeraciones los valores de enumeración individuales se asignan a su base de datos teclas de tabla de búsqueda. Para que pueda obtener su pantalla con aPersonObject.HairColor.ToString(), y puede obtener la ID con aPersonObject.HairColor

Puede obtener realmente elegante y utilizar algunos code-gen (plantillas Mabey T4) para crear sus enums automáticamente a partir de los valores en la base de datos.

+0

Realmente agradezco su opinión pero soy demasiado obtuso para entenderlo en este momento. He usado enumeraciones ... pero principalmente solo como constantes para las decisiones de enunciados de casos. ¿Hay alguna forma de que pueda modificar su respuesta para tener un pequeño código de muestra que pueda cambiar mi interruptor "a ha"? Si tuviera un archivo Person.cs y un archivo PersonManager.cs que contuviera métodos estáticos como GetPeople() o GetPerson() ... ¿dónde vivirían estas enumeraciones ... y cómo se integrarían con mi clase Person? – octechnologist

+0

agregó algo de contenido adicional. Si necesita más aclaración, hágamelo saber. –

+0

El objetivo de una clave foránea es que la lista esté contenida en el almacén de datos, no en tapa dura. –

1

¿Has consultado la "propiedad de navegación" en EF? Te permitirá mantener los ID en la clase principal (es decir, Persona) y hacer referencia a las propiedades de cadena a través de las propiedades de navegación. Por ejemplo, usted tiene:

persona p = [obtener el registro de contexto de datos EF]

p.state_id se refiere a la identificación numérica del Estado, mientras que p.State.Name será el nombre de la cadena del Estado. EF se encarga de cargar el registro de estado referenciado. Incluso puede crearlos automáticamente si usa database-first y tiene definidas sus claves foráneas (hay herramientas que convertirán la base de datos primero en código)

+0

Estoy bastante seguro de que esto tendría mi capa de presentación hablando directamente con las entidades EF, ¿verdad? Prefiero evitar eso como lo mencioné al principio de la pregunta (el área de contexto). A partir de la investigación que he realizado, he comprobado que es una buena práctica para mi capa de negocios ser una abstracción de la capa de persistencia. Presentación -> negocio -> persistencia. Creo que el solo hecho de que trate de usar las ID de SQL rompe este modelo ... pero no es tan "malo" como mi capa de presentación hablando directamente con las entidades. No soy un experto, obviamente ... pero eso es lo que deduzco. – octechnologist

+0

Sí, puede hacer que hablen con las entidades de EF; sin embargo, con código primero, sus entidades de EF son solo clases de POCO que no son diferentes de si las hubiera escrito usted mismo. Sí, podría crear una jerarquía completa de clases en su capa de presentación, pero ¿por qué hacer eso cuando las clases de presentación serán * exactamente * las mismas que las entidades POCO EF? Puede poner las clases EF POCO en un ensamble separado y hacer que ese sea el vehículo para intercambiar datos por todas las diferentes capas. – Tundey

+0

Eche un vistazo a esta herramienta para crear POCOs desde EDMX: http://visualstudiogallery.msdn.microsoft.com/72a60b14-1581-4b9b-89f2-846072eff19d – Tundey

Cuestiones relacionadas