2012-08-14 9 views
9

Estoy trabajando en la reescritura de mi aplicación ASP.NET MVC utilizando los principios de diseño impulsados ​​por el dominio. Estoy tratando de validar mi entidad de usuario. Hasta ahora, puedo validar reglas básicas (como el nombre de usuario y la contraseña como una cadena que no es nula/blanca). Sin embargo, una de las reglas, necesito asegurarme de que el nombre de usuario sea único. Sin embargo, necesito acceder a la base de datos para hacer esto, lo que significa que tendría que inyectar mi IUserservidor en mi entidad de usuario de esa manera.DDD Domain Model Complex Validation

public class User 
{ 
    private readonly IUserRepository _userRepository; 
    public User(IUserRepository repo) 
    { 
     _userRepository = repo; 
    } 

    public override void Validate() 
    { 
     //Basic validation code 
     if (string.IsNullOrEmpty(Username)) 
      throw new ValidationException("Username can not be a null or whitespace characters"); 
     if (string.IsNullOrEmpty(Password)) 
      throw new ValidationException("Password can not be a null or whitespace characters"); 

     //Complex validation code 
     var user = _userRepository.GetUserByUsername(Username); 
     if (user != null && user.id != id) 
      throw new ValidationException("Username must be unique") 
    } 
} 

Sin embargo, esto parece ... bien, está mal. Hacer que mi entidad dependa de mi repositorio parece una mala idea (corrígeme si me equivoco). Pero tener el código de validación en la entidad tiene sentido. ¿Dónde está el mejor lugar para poner código de validación complejo?

+2

Ver también [esta respuesta] (http://stackoverflow.com/a/9676307/706456) – oleksii

Respuesta

8

Sin embargo, esto parece ... muy mal. Hacer que mi entidad dependa de mi repositorio parece una mala idea (corrígeme si me equivoco).

En general, la dependencia del repositorio no es 'incorrecta', a veces es inevitable. Sin embargo, creo que debería ser una excepción y debería evitarse tanto como sea posible. En su escenario, puede reconsiderar tener esta dependencia. Si lo piensas, la "singularidad" no es responsabilidad de la propia entidad porque la entidad no conoce otras entidades. Entonces, ¿por qué la entidad hizo cumplir esta regla?

Pero tener el código de validación en la entidad tiene sentido. ¿Dónde está el mejor lugar para poner código de validación complejo?

Creo que es posible que esté sobrevaluando la "validación". Me desharía del método 'Validar' y me aseguraré de que el objeto no entre en estado 'no válido' en primer lugar. I answered pregunta similar hace unos meses.

Ahora volvamos a la regla de la unicidad. Creo que este es uno de los ejemplos donde DDD 'gotea' un poco, en un sentido que la aplicación de esta regla comercial no puede expresarse puramente en el código de dominio. Me acercaría así:

// repository 
interface Users { 
    // implementation executes SQL COUNT in case of relation DB 
    bool IsNameUnique(String name); 

    // implementation will call IsNameUnique and throw if it fails 
    void Add(User user); 
} 

El código de cliente sabría que antes de añadir un nuevo usuario, se debe comprobar explícitamente la singularidad, de lo contrario se bloqueará. Esta combinación impone reglas comerciales en el código de dominio, pero generalmente no es suficiente. Como capa de aplicación adicional, es posible que desee agregar una restricción ÚNICA en la base de datos o emplear un bloqueo explícito.

4

Sin embargo, esto parece ... bien mal

No, no es malo en absoluto. Tener el modelo de dominio depende de un repositorio está perfectamente bien. Además de eso, ha abstraído su repositorio detrás de una interfaz que es aún mejor.

O no use la inyección de constructor. Pasar el repositorio para el método Validar si es el único que lo necesitan:

public class User 
{ 
    public void Validate(IUserRepository repo) 
    { 
     //Basic validation code 
     if (string.IsNullOrEmpty(Username)) 
      throw new ValidationException("Username can not be a null or whitespace characters"); 
     if (string.IsNullOrEmpty(Password)) 
      throw new ValidationException("Password can not be a null or whitespace characters"); 

     //Complex validation code 
     var user = repo.GetUserByUsername(Username); 
     if (user != null && user.id != id) 
      throw new ValidationException("Username must be unique") 
    } 
} 
+0

Gracias por su respuesta. El problema es que ahora tengo que tener una implementación de IUserRepository para construir un Usuario, lo que significa que tendría que usar el IoC para inyectar las dependencias para las entidades. Esto parece tener más código del que vale, especialmente porque aprovecho los atributos de inicialización al construir el objeto. Ejemplo var user = new User {Username = "Admin"}; –

+0

En este caso, no use la inyección de constructor. Pase el repositorio al método Validate si este es el único que lo necesita. –

1

Estoy de acuerdo con @oleksii, using the specification pattern es un mejor enfoque. La validación tiene diferentes significados en diferentes contextos, por lo que tiene sentido para mí dividir esta preocupación.

8

Un patrón que uso en este tipo de situaciones es colocar este tipo de lógica de validación en el servicio de la aplicación.Hasta cierto punto, esto tiene sentido porque la entidad User solo es responsable de su propia validez, no de la validez del conjunto de usuarios. El método de servicio aplicación que crea el usuario puede looklike esto:

public User CreateUser(string userName) 
{ 
    if (this.userRepository.Exists(userName)) 
    throw new Exception(); 
    var user = new User(userName); 
    this.userRepository.Add(user); 
    return user; 
} 

el servicio de aplicación es una abstracción que está ahí, independientemente de si usted está empleando DDD o no y, por tanto, es un buen lugar para caer de nuevo a cuando DDD da fricción.