from - ASP.NET MVC-¿Entidades de base de datos o modelos de vista?
view model mvc c# (8)
Estaba a punto de agregar exactamente el mismo sentimiento que hackedbychinese. También agregaría, con fk''s a las listas de búsqueda, simplemente TIENE que usar viewmodels ya que el modelo de entidad simplemente mantendrá un puntero a un único ID dentro de esa tabla. Un modelo de vista le permite pasar la lista poblada requerida a la vista - voila.
Además, un modelo de vista puede contener lógica discreta cuando sea necesario, este NO sería el caso con el modelo de entidad. Además, sus validaciones pueden variar según el uso de su vista, por lo tanto, se pueden aplicar diferentes validaciones según el requisito de "vista".
El propósito de un ViewModel es principalmente la separación de preocupaciones, desacoplando la Vista de los detalles de implementación del Modelo.
Actualmente estoy trabajando en un proyecto ASP.NET MVC.
Algunos desarrolladores del equipo desean vincular las entidades de base de datos generadas automáticamente a las Vistas.
Otros desarrolladores quieren crear ViewModel a medida y vincularlos a las Vistas.
Objetivamente, ¿cuáles son los pros y los contras de ambos enfoques?
(Por "entidades de base de datos" me refiero a las clases generadas automáticamente que genera un marco ORM, como LINQ to SQL, Entity Framework o LLBLGen).
Gracias por las respuestas hasta ahora; han sido de gran ayuda para comprender los pros / contras de ambos enfoques. Tengo una cosa que añadir que nadie más ha mencionado.
Ataque de sobre-publicación
Una desventaja preocupante con la vinculación directa contra las entidades de BD es un "ataque de sobre-publicación". Aquí es donde el atacante, utilizando una herramienta no más avanzada que FireBug, puede insertar campos de formulario que el usuario no puede editar, pero que existen en la entidad DB.
Considere una página "Editar mi perfil". Su vista puede verse así:
@using(Html.BeginForm() {
<div>
@Html.LabelFor(x=> x.FirstName)
@Html.TextBoxFor(x=> x.FirstName)
</div>
<div>
@Html.LabelFor(x=> x.LastName)
@Html.TextBoxFor(x=> x.LastName)
</div>
<input type="Submit" value="Save" />
}
Haría el siguiente HTML:
<form action="/profile/edit" method="post">
<div>
<label for="FirstName">FirstName</label>
<input type="text" name="FirstName" value="" />
</div>
<div>
<label for="LastName">LastName</label>
<input type="text" name="LastName" value="" />
</div>
<input type="Submit" value="Save" />
</form>
Con FireBug, un atacante solo necesita insertar un fragmento de HTML dentro del formulario:
<input type="hidden" name="IsAdmin" value="true" />
... y de repente los usuarios pueden cambiar los datos de maneras muy inesperadas y dañinas.
Aquí hay algunos campos de formularios ocultos aún más temibles:
<input type="hidden" name="ShoppingCart.Items[0].Price" value="0.01" />
<input type="hidden" name="BankAccount.Balance" value="1000000" />
<input type="hidden" name="User.Administrator.Password" value="hackedPassword" />
¡Ay!
Información tomada de: http://hendryluk.wordpress.com/tag/asp-net-mvc/
La ortodoxia es que nunca debe usar sus entidades de base de datos sin procesar en sus vistas. Como cualquier regla, se puede romper si conoce bien sus entidades y comprende las consecuencias, pero existen muy buenas razones para no violar esa regla, particularmente cuando se trabaja en equipo y con un código que las personas mantendrán en el futuro. quién podría no entender la regla o las entidades tan bien como tú. Las principales razones son:
Carga lenta de ORM Imagine que su cliente tiene una colección de pedidos cargados de pereza. Pasa al Cliente a la Vista e itera sobre Pedidos. Obtiene una selección N * 1 en la tabla Pedidos. Pero también significa que su conexión a la base de datos aún debe estar abierta en la Vista. Existe un patrón en el que las personas usan ''Transacción por acción'' que elimina el contexto de la base de datos en el evento Action_Executed, que ocurre antes de que se visualice su vista. Por lo tanto, podría estar intentando acceder a la base de datos después de haber sido eliminada. Incluso si no está haciendo eso ahora, alguien en el futuro podría decidir implementar ese patrón porque está de moda.
Las preocupaciones del ViewModel son diferentes al modelo db. Por ejemplo, normalmente decora sus propiedades de ViewModel con atributos de validación. Estos suelen ser diferentes o solo se refieren a la interfaz de usuario, no a la base de datos. Si se vincula a las entidades de su base de datos, encontrará todas estas preocupaciones de UI contaminando sus entidades DB.
Relacionado con 2: los requisitos de ViewModel pueden exigir propiedades calculadas o derivadas. Por ejemplo, un nombre completo construido a partir de nombres y apellidos. Este tipo de cosas se conserva mejor en ViewModel.
Puede probar sus ViewModels de forma aislada de la base de datos. ViewModels puede terminar conteniendo mucha lógica que necesita ser probada por la unidad. Esto es más fácil de probar si no está vinculado a su base de datos (como con entidades EF).
En general, crear y mantener ViewModels (incluso sin AutoMapper) no es una sobrecarga y verá que es un patrón de desarrollo mucho mejor en general. Lo recomendaría para todo menos para los casos más simples (listas de búsqueda de datos estáticos, por ejemplo).
No exponga entidades de backend al cliente. La aplicación del mundo real tiene un comportamiento, no CRUD. Si relaciona sus entidades con la información, será solo una cuestión de tiempo antes de que incursione en la piratería cuando se requiere un comportamiento en el lado del cliente.
Una vez intenté desarrollar una aplicación que utilizaba entidades NHibernate directamente en vistas de ASP.NET. Me encontré con muchos problemas con la carga diferida y la ejecución diferida de SQL que se ejecutaba directamente desde las vistas en lugar de en la capa de lógica de negocios o incluso en los controladores. Pasar a viewmodels y usar Automapper pareció resolver todos estos problemas y hacer que la aplicación sea más fácil de probar, depurar y mantener.
También encontré que los modelos de vista eran útiles para contener todos los datos asociados que necesitaba en una página. A algunos desarrolladores les gusta usar el ViewBag dinámico para esto, pero esto es malo para las pruebas y la depuración.
En particular, ver modelos facilitó la elección de entidades asociadas de listas desplegables.
AutoMapper fue un salvavidas en este proyecto, ya que ahorró tener que escribir una tonelada de código de mapeo, todo lo que tenía que hacer era crear los modelos de vista y luego los controladores se automatizaban desde las entidades para ver los modelos.
Usar entidades de BD en sus vistas, especialmente sus formularios, es un problema de seguridad masivo . Tome el siguiente objeto POCO
public class User
{
public int Id { get; set; }
public string Username { get; set; }
public string Email { get; set; }
public bool IsAdmin { get; set; }
}
Ahora diga que está presentando una vista que permite a un usuario cambiar su correo electrónico. El método MVC para procesar el resultado del formulario al usar las entidades Db en lugar de los modelos de vista se vería así: (a menos que no utilice el enlace del modelo, en cuyo caso está haciendo más trabajo para usted)
public class HomeController : Controller
{
[HttpPost]
public ActionResult ChangeEmail(User user)
{
//....
}
}
El enlace de modelo en Asp.net funciona buscando los parámetros GET o POST que coinciden con los nombres de las propiedades en el modelo. Por lo tanto, todo lo que el usuario tiene que hacer es agregar IsAdmin=true
a los parámetros POSt y viola, el modelo pasado a la función ChangeEmail
tendrá la propiedad IsAdmin establecida en verdadero, que podría agregarse fácilmente a la base de datos, dando a los usuarios la libertad acceso para cambiar datos a los que no tuvieron acceso para cambiar.
Esto se aplica a los permisos del usuario, cambiando quién posee una entidad (haga que su pregunta se asocie conmigo en lugar de usted), cambie las fechas de creación originales, etc.
Creo que usar modelos de vista es la única manera de hacerlo, por lo que no hay ventajas para entidades ORM :) Los modelos de vista no solo proporcionan datos para la vista, sino que también definen cómo debe verse la vista (definiendo plantillas) o cómo debe validarse (añadiendo anotaciones de datos o implementando IDataErrorInfo).
Usando modelos de vista:
Pros:
- Los modelos de vista contienen solo propiedades requeridas por vista, nada más.
- Los modelos de vista pueden contener reglas de validación específicas usando anotaciones de datos o IDataErrorInfo.
- Los modelos de vista pueden combinar valores de diferentes entidades de base de datos.
- Los modelos de vista se documentan a sí mismos y no están vinculados a ningún marco.
- Los modelos de vista lo protegen de POST falsos, que contienen valores, que no se proporcionaron en forma, pero que estaban contenidos en entidades ORM.
- Puede especificar plantillas de visualización para ver modelos y reutilizarlos en muchos lugares utilizando
DisplayFor
oEditorFor
helpers.
Usando entidades ORM:
Contras:
- Las entidades ORM ya contienen anotaciones de datos que pueden arruinar su validación. Ejemplo: el campo de contraseña en el usuario puede marcarse como
Required
, pero no es obligatorio cuando solo se modifica la información básica del usuario. - Las entidades ORM están fuertemente ligadas a Framework (Entity Framework) y puede que no sea fácil implementar las reglas en.
- Las entidades ORM pueden contener propiedades para más de una vista, pero es difícil separar las reglas de validación para diferentes vistas.
- El uso de entidades ORM con carga diferida puede llevarlo a ejecutar consultas SQL cuando se procesan las vistas. No debería suceder.
- El uso de entidades ORM puede llevar a utilizar grandes consultas SQL en lugar de pequeñas. Cuando desee mostrar el menú desplegable con nombre y apellido, solo debe recuperar el nombre y el apellido de la base de datos, no las entidades enteras.
Definitivamente use los modelos de vista en sus vistas , y use algo como AutoMapper
para crear modelos de vista de entidades fácilmente.
Contras:
- A veces se siente como si estuvieras duplicando código, específicamente, cuando el modelo de vista y la entidad tienen exactamente las mismas propiedades
Pros:
- A menudo necesita representar un objeto en un formato más simple (a menudo llamado aplanamiento), pero necesita fidelidad total en el lado del servidor. Esto le permite hacer la transición entre los dos sin ensuciar su modelo de dominio con la presentación de cruft.
- Las raíces agregadas a menudo tienen muchos objetos de valor y entidades adicionales que son irrelevantes para una vista específica, y omitirlas en un modelo de vista hace que sea más fácil trabajar con ellas.
- Sus entidades tendrán muchas referencias de dos vías que son sensatas en términos de una API, pero crean infierno cuando las serializan para JSON, XML, etc. Los modelos de vista eliminarán estas referencias circulares.
- A menudo puede usar la misma entidad pero de diferentes maneras para diferentes vistas. Tratar de equilibrar ambas necesidades en un tipo puede crear un gran desastre.