Estoy tratando de que EF 4.1 trabaje con Repository, UnitOfWork, separación de entidades de EF y validación.Entity Framework IValidatableObject reference DbContext
Seguí this guía para obtener una buena separación de mis entidades POCO del modelo EF y ahora estoy siguiendo la guía this para implementar la validación (con IValidatableObject).
Mi solución consiste en:
- Contacts.Repository [referencias EF y Contacts.Entities]:
- Contacts.edmx
- ContactsDbContext.cs
- Contacts.Entities [sin referencias]:
- Contact.cs (clase Contacts.Entities.Contact parcial)
- Contacts.Validation [referencias Contacts.Entities y Contacts.Repository]
- Contact.cs (Contacts.Entities.Contact clase parcial)
Pero estoy golpeando una pared de ladrillo con la validación:
- No puedo agregar la lógica de validación a Contacts.Entities porque causaría una referencia circular con Contacts.Repository (contact.Validate (...) necesita usar ContactsDbContext). Así que creé un proyecto separado de Contacts.Validation.
- Pero, esto significa dividir la clase de contacto con clases parciales para definir el contacto dentro de ambos Contacts.Entities y Contacts.Validation. El código ya no se compila porque no se puede definir una clase parcial en diferentes conjuntos.
¿Alguien me ha dado algún consejo aquí? He colgado debajo del código ...
Contacts.Repository.ContactsDbContext.cs:
namespace Contacts.Repository
{
public partial class ContactsDbContext : DbContext
{
public DbSet<Contact> Contacts { get; set; }
protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
{
items.Add("Context", this);
return base.ValidateEntity(entityEntry, items);
}
}
}
Contacts.Entities.Contact.cs:
namespace Contacts.Entities
{
public partial class Contact
{
public string Name { get; set; }
}
}
Contacts.Validation.Contact. cs contiene:
namespace Contacts.Entities
{
public partial class Contact : IValidatableObject
{
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
ContactsDbContext contacts = (ContactsDbContext)validationContext.Items["Context"];
//Check if Contact already exists with the same Name
if (contacts.Any<Contact>(c => c.Name == this.Name))
yield return new ValidationResult("Contact 'Name' is already in use.", new string[] { "Name" });
yield break;
}
}
Gracias. - Eso es un paso más cerca. Estoy de acuerdo, preferiría más separación de preocupaciones. ¿Cómo separarías normalmente la Validación del Repositorio (independientemente de EF)? Tengo un buen patrón de Validación y Repositorio que proporciona una separación completa ... pero luego tiene el problema de que la persona que llama no puede llamar al Validate antes de llamar al Guardar en el Repositorio. NB: ahora tengo que hacer referencia a Entity Framework en los llamadores porque la validación generará un tipo System.Data.Entity.Validation.DbEntityValidationException. Estoy descubriendo que esta es una pelea molesta contra EF !!! – Matt
@Matt: No tengo una separación clara entre la validación y el repositorio. La validación de que un campo particular debe ser único es desde mi punto de vista, no una validación a nivel de entidad. También podría considerarse como una validación del repositorio (el repositorio se volvería inválido * si * insertaría una entidad con el mismo nombre). Normalmente accedo a mis repos a través de clases de servicio y allí hago un "chequeo" antes de insertar si ya hay una entidad con el mismo nombre. No es una validación limpiamente separada. Puede ser más fácil y más limpio cuando EF proporciona la característica "Restricciones únicas" mencionada en la segunda publicación del blog. – Slauma
Estoy usando DataAnnotation para proporcionar validación de nivel de entidad. Estoy de acuerdo en que la verificación de unicidad es un nivel de validación diferente y no debería estar realmente en la entidad. TBH, siento que EF me está forzando a seguir este camino. Veré cómo moverlo al repositorio. Gracias por tu ayuda. – Matt