2010-01-26 9 views
6

Tengo un modelo de dominio ignorante de persistencia que usa repositorios abstractos para cargar objetos de dominio. La implementación concreta de mis repositorios (la capa de acceso a datos (DAL)) utiliza el marco de entidades para obtener datos de una base de datos de servidor SQL. La base de datos tiene restricciones de longitud en muchas de sus columnas varchar. Ahora imagina que tengo la siguiente clase de dominio:Restringir longitud de cadena en las clases de dominio

public class Case 
{ 
    public Case(int id, string text) 
    { 
     this.Id = id; 
     this.Text = text; 
    } 

    public int Id { get; private set; } 
    public string Text { get; set; } 
} 

Y un repositorio abstracta definida de la siguiente manera:

public abstract class CaseRepository 
{ 
    public abstract void CreateCase(Case item); 
    public abstract Case GetCaseById(int id); 
} 

La columna [text] de la tabla en SQL Server se define como nvarchar(100)

Ahora Sé que mencioné que mi clase de dominio (Case) era persistente ignorante, sin embargo, creo que está mal que permita para los valores de text parámetro que no puede ser salvado por mi implementación concreta de repositorio porque la estructura de entidad arrojará una excepción al asignar la propiedad text a la clase generada por el marco de entidad cuando tiene más de 100 caracteres. Así que he decidido que deseo verificar esta restricción en el modelo de dominio, porque esto me permite verificar la validez de los datos antes de intentar pasarlos al DAL, y así hacer que los informes de error sean más centrados en el objeto de dominio. Creo que se puede argumentar que solo yo pueda comprobar la restricción en mi constructor y en la incubadora propiedad, pero ya que tengo cientos de clases que todos tienen las mismas limitaciones que quería una manera más genérico para resolver el problema

Ahora , lo que yo he llegado con una clase llamada ConstrainedString, que se define de la siguiente manera:

public abstract class ConstrainedString 
{ 
    private string textValue; 

    public ConstrainedString(uint maxLength, string textValue) 
    { 
     if (textValue == null) throw new ArgumentNullException("textValue"); 
     if (textValue.Length > maxLength) 
      throw new ArgumentException("textValue may not be longer than maxLength", "textValue"); 

     this.textValue = textValue; 
     this.MaxLength = maxLength; 
    } 

    public uint MaxLength { get; private set; } 

    public string Value 
    { 
     get 
     { 
      return this.textValue; 
     } 

     set 
     { 
      if (value == null) 
       throw new ArgumentNullException("value"); 
      if (value.Length > this.MaxLength) throw new ArgumentException("value cannot be longer than MaxLength", "value"); 
      this.textValue = value; 
     } 
    } 
} 

Además tengo una implementación de ConstrainedString llamada String100:

public class String100 : ConstrainedString 
{ 
    public String100(string textValue) : base(100, textValue) { } 
} 

Lo que conduce a una implementación diferente de Case que se vería así:

public class Case 
{ 
    public Case(int id, String100 text) 
    { 
     this.Id = id; 
     this.Text = text; 
    } 

    public int Id { get; private set; } 
    public String100 Text { get; set; } 
} 

Ahora, mi pregunta es; ¿Estoy pasando por alto algunas clases incorporadas o algún otro enfoque que podría usar en su lugar? ¿O es este un enfoque razonable?

Cualquier comentario y sugerencia son bienvenidos.

gracias de antemano

+0

+1 Buena pregunta - A menudo me he preguntado por qué tales tipos no existen en el BCL. Sin embargo, creo que huele a Leaky Abstraction que está permitiendo que la base de datos relacional influya de esa manera en el Modelo de Dominio, o ¿existe un motivo convincente de dominio para estas restricciones? –

+0

@Mark Seemann Estoy de acuerdo contigo en que huele, y no, en la mayoría de las partes no hay una razón de dominio convincente para las restricciones. Básicamente, es un esquema de base de datos heredado que probablemente podría beneficiarse de algunas refactorizaciones, pero eso está fuera de nuestro alcance actual. Sin embargo, no creo que pueda ignorar estas limitaciones en el modelo porque quiero hacer de la validación de datos una parte del modelo y NO una parte de la implementación del repositorio (que creo que es una buena ambición) –

+0

¡Ah, el maravilloso mundo de aplicaciones heredadas ... Considere la posibilidad de crear una capa Decorator para su Modelo de dominio que implemente estas restricciones para mantener limpio su Modelo de dominio. Consulte aquí para obtener más detalles: http://community.ative.dk/blogs/ative/archive/2006/09/29/Migration-_2D00_-Bug_2D00_by_2D00_Bug-Compatibility.aspx –

Respuesta

1

Creo que su validación debe residir en su modelo de dominio. Las restricciones en sus campos representan directamente una lógica comercial. En última instancia, debe validar antes de persistir de todos modos.

0

creo que esto depende de muchos factores (así como algunas preferencias personales). A veces la restricción debe formar parte del objeto de dominio, por ejemplo, con números de seguridad social/pasaporte ... estos normalmente tienen una longitud fija y no pueden variar como una regla de dominio, no una regla de persistencia de datos (aunque puede restringir la base de datos también).

Algunos prefieren no tener este tipo de controles en su modelo de dominio y en su lugar tienen algo así como un atributo de validación en la propiedad que puede ser inspeccionado y ejecutado externamente desde el objeto de dominio por un validador independiente.

El problema que puede tener con su método (aunque no es difícil de obtener) es obtener cualquier ORM/Mapper, si está utilizando uno, para saber cómo asignar una cadena a/desde el DB a su ConstrainedString.

El ConstrainedString podría no conseguir alrededor de la cuestión del objeto de dominio que tiene información adicional sobre la restricción, ya que puede ser que necesite para construir el ConstrainedString

+0

La pregunta dice que Entity Framework es el ORM. –

0

Si cambia las restricciones de un caso, tiene sentido que tenga que crear uno nuevo: ha cambiado el contrato y el código anterior ya no sabrá si cumple los requisitos o no.

lugar de preocuparse por lo que su repositorio o no permitirá, define lo que va a permitir que en su clase, y asegúrese de que encontrar una manera de trabajar con cualquier repositorio que cambie en el futuro. Tienes tu API, tus dependencias no.

Cuestiones relacionadas