ASP.NET MVC - ¿Entidades de base de datos o ViewModels?


Actualmente estoy trabajando en un ASP.NET Proyecto MVC.

Algunos desarrolladores del equipo quieren vincular las entidades de base de datos generadas automáticamente directamente a las vistas.

Otros desarrolladores quieren crear modelos de vista personalizados 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 framework framework, como LINQ to SQL, Entity Framework o LLBLGen).

Author: Alex York, 2012-06-07

8 answers

Definitivamente use modelos de vista en sus vistas, y use algo como AutoMapper para crear modelos de vista a partir de entidades fácilmente.

Contras:

  1. A veces se siente como si estuviera duplicando código, específicamente, cuando el modelo de vista y la entidad tienen exactamente las mismas propiedades

Ventajas:

  1. A menudo necesita representar un objeto en un formato más simple (a menudo llamado aplanamiento), pero necesita fidelidad completa en el lado del servidor. Esto le permite hacer la transición entre los dos sin arruinar su modelo de dominio con presentation cruft.
  2. Las raíces agregadas a menudo tienen muchos objetos de valor y entidades adicionales que son irrelevantes para una vista específica, y omitirlos en un modelo de vista hace que sea más fácil trabajar con ellos.
  3. Sus entidades tendrán un montón de referencias de dos vías que son sensibles en términos de una API, pero crean un infierno puro al serializarlas para JSON, XML, etc. Los modelos de vista eliminarán estas referencias circulares.
  4. Usted 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 lío.
 47
Author: HackedByChinese,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-07 10:01:43

La ortodoxia es que nunca debe usar sus entidades de base de datos sin procesar en sus vistas. Como cualquier regla, está ahí para romperse si conoces bien tus entidades y entiendes las consecuencias, pero hay muy buenas razones para no romper esa regla, particularmente cuando trabajas en equipos y con código que será mantenido en el futuro por personas que podrían no entender la regla o las entidades tan bien como tú. Las razones principales son:

  1. Lazy carga lenta. Imagine su cliente tiene un perezoso cargado Pedidos de recogida. Pasa el Cliente a la vista y itera sobre los pedidos. Obtienes un N * 1 select en la tabla de Pedidos. Pero también significa que la conexión de la base de datos aún debe estar abierta en la vista. Hay un patrón 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 renderice su vista. Por lo tanto, podría estar tratando de acceder a la base de datos después de que se haya eliminado. Aunque usted no está haciendo eso ahora, alguien en el futuro podría decidir implementar ese patrón porque está de moda.

  2. Las preocupaciones del ViewModel son diferentes al Modelo db. Por ejemplo, normalmente decora las propiedades de ViewModel con atributos de validación. Por lo general, son diferentes o solo se refieren a la interfaz de usuario, no a la base de datos. Si se enlaza a las entidades de la base de datos, encontrará que todas estas preocupaciones de la interfaz de usuario contaminan las entidades de la base de datos.

  3. Relacionado con 2 - los requisitos del ViewModel pueden exigir propiedades calculadas o derivadas. Por ejemplo, un Nombre completo construido a partir de Nombres y Apellidos. Este tipo de cosas se guardan mejor en ViewModel.

  4. Puede probar unitariamente sus ViewModels aisladamente de la base de datos. ViewModels puede terminar contiene mucha lógica que necesita probarse. Esto es más fácil de probar si no está vinculado a su base de datos (como con las entidades EF).

En general, crear y mantener ViewModels (incluso sin AutoMapper) no es una sobrecarga y encontrará que es un patrón mucho mejor de desarrollo en general. Lo recomendaría para todo menos para los casos más simples (listas de búsqueda de datos estáticos, por ejemplo).

 16
Author: Rob Kent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-21 15:09:52

Creo que el uso de modelos de vista es el único camino a seguir, por lo que no hay ventajas para las entidades OR:) Los modelos de vista no solo proporcionan datos para view, sino que también definen cómo debe verse view (definiendo plantillas) o cómo debe validarse (agregando anotaciones de datos o implementando IDataErrorInfo).

Usando modelos de vista:

Ventajas:

  • Los modelos de vista solo contienen las propiedades requeridas por view, nada más.
  • Los modelos de vista pueden contener reglas de validación 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 framework.
  • Los modelos de vista lo protegen de mensajes falsos, que contienen valores, que no se proporcionaron en forma, pero que estaban contenidos en entidades OR.
  • Puede especificar fácilmente plantillas de visualización para ver modelos y reutilizarlas en muchos lugares utilizando DisplayFor o EditorFor ayudante.

Usando entidades OR:

Contras:

  • Las entidades OR ya contienen anotaciones de datos, que pueden estropear su validación. Ejemplo: El campo de contraseña en el usuario puede ser markes como Required, pero no es necesario cuando se cambia solo la información básica del usuario.
  • Las entidades OR están fuertemente vinculadas a Framework (Entity Framework) y puede que no sea fácil implementar reglas en ellas.
  • Las entidades OR 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 OR con carga diferida puede llevarlo a ejecutar consultas SQL cuando se renderizan vistas. No debería pasar.
  • El uso de entidades OR puede llevar al uso de consultas SQL enormes en lugar de pequeñas. Cuando desee mostrar el menú desplegable con el nombre y el apellido, solo debe recuperar el nombre y el apellido de la base de datos, no entidades enteras.
 12
Author: LukLed,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-07 09:34:19

Gracias por las respuestas hasta ahora - han sido una gran ayuda en la comprensión de los pros/contras de ambos enfoques. Tengo una cosa que añadir que nadie más ha mencionado.

Over-posting attack

Una desventaja preocupante con el enlace directamente contra las entidades de base de datos 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 no están destinados a ser editables por el usuario, pero que existen en la base de datos entidad.

Considere una página de "Editar mi perfil". Su vista podría 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" />
}

Renderizarí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>

Usando FireBug, un atacante simplemente necesita insertar un trozo 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 formulario ocultos aún más aterradores:

  <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" />

Ouch!

Información tomada de: http://hendryluk.wordpress.com/tag/asp-net-mvc /

 8
Author: Alex York,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-07 21:59:38

Una vez traté de desarrollar una aplicación que utiliza entidades NHibernate directamente en ASP.NET vistas. Me encontré con muchos problemas con la carga lenta y la ejecución SQL diferida que se ejecuta directamente desde las vistas en lugar de en la capa de lógica de negocio o incluso controladores. Pasar a viewmodels y usar automapper parecía resolver todos estos problemas y hacer que la aplicación fuera más fácil de probar, depurar y mantener.

También encontré que los modelos de vista eran útiles para mantener todos los datos asociados que necesitaba en un pagina. A algunos desarrolladores les gusta usar el ViewBag dinámico para esto, pero esto es malo para probar y depurar.

En particular, ver modelos hizo que fuera fácil cuando quería elegir entidades asociadas de las listas desplegables.

AutoMapper fue un salvavidas en este proyecto, ya que ahorró tener que escribir una tonelada de código de asignación, todo lo que tuve que hacer fue crear los modelos de vista y luego los controladores se automatizaron desde entidades para ver modelos.

 5
Author: gls123,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-07 09:41:51

No exponga las entidades backend al cliente. Aplicación del mundo real tienen comportamiento-no CRUD. Si usted databind sus entidades a la vista que solo será cuestión de tiempo antes de que usted cavar en el truco barro cuando se requiere el comportamiento en el lado del cliente.

 3
Author: Lars-Erik Roald,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-07 11:43:21

Estaba a punto de añadir exactamente el mismo sentimiento que hackedbychinese. también agregaría, con las listas de búsqueda de fk, solo TIENE que usar viewmodels ya que el modelo de entidad simplemente sostendrá un puntero a un solo id dentro de esa tabla. Un viewmodel le permite pasar la lista poblada requerida a la vista-voila.

Además, un viewmodel puede contener lógica discreta cuando sea necesario, esto definitivamente NO sería el caso con el entity model. Además, sus validaciones pueden variar dependiendo de la uso de su vista, por lo tanto, se pueden aplicar diferentes validaciones por requisito de 'vista'.

El propósito de un ViewModel es principalmente la separación de preocupaciones - desacoplar la Vista de los detalles de implementación del Modelo.

 1
Author: jim tollan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-07 08:47:01

Usar entidades de base de datos 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 supongamos 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 cuando se usan Entidades de base de datos en lugar de modelos de vista se vería así: (a menos que no use el enlace de modelo, en cuyo caso está haciendo más trabajo para usted mismo)

public class HomeController : Controller
{
    [HttpPost]
    public ActionResult ChangeEmail(User user)
    {
        //....
    }
}

Enlace de modelo en Asp.net funciona buscando GET o POST parámetros que coincidan 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 true, que muy fácilmente podría agregarse accidentalmente a la base de datos, dando a los usuarios acceso libre para cambiar los datos que no tenían acceso para cambiar.

Esto se aplica a los permisos de usuario, cambiando quién posee una entidad (haga que su pregunta se asocie conmigo en su lugar de ti), cambiar las fechas de creación originales, etc...

 0
Author: KallDrexx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-14 03:58:42