asp.net-mvc - ventajas - mvc php
Usando MVC y Nhibernate con fluidez, ¿cómo valido los campos únicos en mi ViewModel antes de vincularlos a mi objeto de dominio y guardarlos? (6)
He encontrado que la solución que funciona para mí es
1.) Pregunte si la entidad es válida para ejecutar su trabajo de validación.
2.) Después de que esto se complete, debe tener algo en su objeto para mostrar que es válido o no (en mi caso, uso un concepto similar a CSLA de "reglas rotas").
3.) Si tiene algo como esto, puede verificar que el objeto sea válido antes de que NHibernate intente persistir como se muestra a continuación.
El único problema con este enfoque es que debe implementar una interfaz en cada entidad que requiera validación. Si puedes vivir con esto, evitará que NHibernate persista en los cambios de un objeto que no es válido según tus reglas.
using System;
using NHibernate;
using NHibernate.Event;
using Validation.Entities.Interfaces;
using Persistence.SessionBuilder;
namespace Persistence.Validation
{
public class ValidationEventListener : IPreInsertEventListener, IPreUpdateEventListener
{
public bool OnPreInsert(NHibernate.Event.PreInsertEvent @event)
{
var entityToInsert = @event.Entity as IBusinessBase;
if (entityToInsert != null)
{
if (entityToInsert.BrokenRules != null)
{
RollbackTransactionBecauseTheEntityHasBrokenRules();
}
}
return false;
}
public bool OnPreUpdate(NHibernate.Event.PreUpdateEvent @event)
{
var entityToUpdate = @event.Entity as IBusinessBase;
if (entityToUpdate != null)
{
if (entityToUpdate.BrokenRules != null)
{
RollbackTransactionBecauseTheEntityHasBrokenRules();
}
}
return false;
}
private void RollbackTransactionBecauseTheEntityHasBrokenRules()
{
try
{
ISession session = SessionBuilderFactory.GetBuilder().CurrentSession;
if (session != null)
{
session.Transaction.Rollback();
}
}
catch (Exception ex)
{
//this will force a rollback if we don''t have a session bound to the current context
throw new NotImplementedException();
}
}
}
}
Tengo un sitio web donde les permito a los usuarios crear nuevos registros de piezas. Estoy tratando de descubrir la mejor manera de validar campos específicos para la singularidad. Quiero asegurarme de que alguien no intente agregar una Parte con el Número de Parte 1234 si ese Número de Partida ya existe en una Parte diferente.
La aplicación web está utilizando Asp.net MVC con fluencia nHibernate para asignar mis objetos a la base de datos. Estoy usando la validación de Castle en mis modelos de vista para cosas como ValidateNonEmpty, ValidateRange, etc. ¿Debería usar el método ValidateSelf para consultar el repositorio y ver si ese número de parte ya existe? Algo no se siente bien con el uso de mi Repositorio en ViewModel.
¿Sería mejor para mí colocar esa lógica en la acción del controlador? Eso no parece correcto porque espero que mi ViewModel ya esté Validado en el punto (durante ModelBind).
O tal vez no sea ninguno de los anteriores. Gracias por cualquier ayuda en este caso.
ACTUALIZAR Bien, no estoy seguro si esto ayudará, pero aquí es cómo se ve mi acción Guardar para una típica Acción de Crear en mi proyecto:
public ActionResult Create(PartViewModel viewModel)
{
//I think I''d like to know if its Valid by this point, not on _repository.Save
if(ModelState.IsValid)
{
try
{
var part = _partCreateViewModelMap.MapToEntity(viewModel);
_repository.Save(part);
return Redirect("~/Part/Details/" + part.Id);
}
catch (Exception e)
{
// skip on down...
}
}
// return view to edit
return View(viewModel);
}
Me han hecho esta pregunta muchas veces. Mis amigos estaban preocupados acerca de si pueden realizar el acceso a los datos desde el código del validador. La respuesta es simple. Si necesita hacer esto, debe hacerlo. Por lo general, necesitamos hacer tales controles en cada nivel de abstracción. Y después de todos los controles, debe estar preparado para detectar una excepción causada por una violación de restricción única.
No tengo respuesta para su pregunta, pero puede consultar el sitio sharparchitecture.net. Contiene algunas de las mejores prácticas para asp.net mvc y nhibernate. También puedo recomendarle que compruebe el proyecto xval y los tutoriales sobre Validación con validadores de anotación de datos
Si define una restricción única dentro de la base de datos, ¿por qué no delega la responsabilidad para verificar si ya existe un valor único en la base de datos? Con NHibernate, puede utilizar la interfaz NHibernate.Exceptions.ISQLExceptionConverter
para capturar y transformar los errores conocidos relacionados con las violaciones de restricciones. También puede usar los ejecutores NHibernate.Exceptions.IViolatedConstraintNameExtracter
(consulte NHibernate.Exceptions.TemplatedViolatedConstraintNameExtracter
) para obtener detalles sucios de la base de datos y transformarlo en un mensaje fácil de usar, reempaquetar como una excepción de validación de su elección y atraparlo en el controlador relevante.
Ejemplo de un convertidor de excepciones rápido, sucio y muy específico de uno de mis proyectos:
Imports NHibernate
Imports NHibernate.Exceptions
Imports System.Data.SqlClient
Imports System.Data.Common
Namespace NHibernate
Public Class ConstraintViolationExceptionConverter
Implements ISQLExceptionConverter
Public Function Convert(ByVal adoExceptionContextInfo As Global.NHibernate.Exceptions.AdoExceptionContextInfo) As System.Exception Implements Global.NHibernate.Exceptions.ISQLExceptionConverter.Convert
Dim dbEx As DbException = ADOExceptionHelper.ExtractDbException(adoExceptionContextInfo.SqlException)
If TypeOf dbEx Is SqlException Then
Dim sqlError As SqlException = DirectCast(dbEx, SqlException)
Select Case sqlError.Number
Case 547
Return New ConstraintViolationException(adoExceptionContextInfo.Message, adoExceptionContextInfo.SqlException)
End Select
End If
Return SQLStateConverter.HandledNonSpecificException(adoExceptionContextInfo.SqlException, adoExceptionContextInfo.Message, adoExceptionContextInfo.Sql)
End Function
End Class
End Namespace
Configurado a través del elemento de propiedad web.config/nhibernate-configuration/session-factory
:
<property name="sql_exception_converter">csl.NHibernate.ConstraintViolationExceptionConverter, csl</property>
Editar: Debería mencionar que la interfaz del convertidor ha cambiado en las versiones recientes de NHibernate, la interfaz de este ejemplo es de NHibernate.dll v2.1.0.4000
Normalmente pongo una capa de servicio entre mis controladores y repositorios.
La capa de servicio manejaría entonces la validación y las llamadas al repositorio.
Luego, si hay un error de validación en la capa de servicio, lanzo una excepción personalizada, la atrapo en el controlador e inserto los errores en el estado del modelo.
Yo diría que esto importa en su arquitectura. Con las aplicaciones de MVC que he hecho en el pasado, abstraemos las cosas del dominio de las cosas de la web y, naturalmente, utilizamos la inyección de dependencia para evitar dependencias duras.
Cuando se trata de validar el modelo cuando está en el momento de vincularlo, sí, podría usar fácilmente el servicio, el repositorio o lo que sea que tenga a continuación en su arquitectura en un método ValidateSelf. Creo que surge la pregunta de qué pasa con esa dependencia.
Si recuerdo correctamente, puede crear su propia carpeta personalizada que usará su marco de inyección de dependencia para conectar cualquier servicio que su modelo necesite para la validación al crearla, llame al encuadernador predeterminado de MVC para rellenar el objeto y luego llame al marco de Castle Validation para hacer la validación Esta no es una solución totalmente pensada, pero con suerte provoca algunas ideas.