with update mvc how framework and c# asp.net-mvc entity-framework repository-pattern viewmodel

c# - update - Consultas de MVC ViewModels y Entity Framework



mvc entity framework relationships (5)

El repositorio debe funcionar solo con modelos que no sean de tipo anónimo y solo debe implementar operaciones CRUD. Si necesita algo de filtrado, puede agregar una capa de servicio para eso.

Para la asignación entre ViewModels y modelos, puede utilizar cualquiera de las bibliotecas de asignación, como Automapper .

Soy nuevo tanto en MVC como en Entity Framework y tengo una pregunta sobre la forma correcta / preferida de hacerlo.

De alguna manera he estado siguiendo la aplicación de Nerd Dinner MVC sobre cómo estoy escribiendo esta aplicación. Tengo una página que tiene datos de diferentes lugares. Muestra detalles que provienen de unas pocas tablas diferentes y también tiene una lista desplegable de una tabla de búsqueda.

Creé una clase ViewModel que contiene toda esta información:

class DetailsViewModel { public List<Foo> DropdownListData { get; set; } // comes from table 1 public string Property1 { get; set; } public string Property2 { get; set; } public Bar SomeBarObject { get; set; } // comes from table 2 }

En el código de Nerd Dinner, sus ejemplos son demasiado simplistas. El DinnerFormViewModel toma en una sola entidad: la cena. Basado en la cena, crea una lista de selección para los países según la ubicación de las cenas.

Debido a la simplicidad, su código de acceso a datos también es bastante simple. Tiene un simple DinnerRepository con un método llamado GetDinner (). En sus métodos de acción él puede hacer cosas simples como:

Dinner dinner = new Dinner(); // return the view model return View(new DinnerFormViewModel(dinner));

O

Dinner dinner = repository.GetDinner(id); return View(new DinnerFormViewModel(dinner));

Mi consulta es mucho más compleja que esto, extrayendo de varias tablas ... creando un tipo anónimo:

var query = from a in ctx.Table1 where a.Id == id select new { a.Property1, a.Property2, a.Foo, a.Bar };

Mi pregunta es la siguiente:

¿Cómo debería ser mi clase de repositorio? ¿Debería la clase de repositorio devolver el ViewModel? Esa no parece ser la forma correcta de hacer las cosas, ya que el tipo de ViewModel implica que se está utilizando en una vista. Dado que mi consulta está devolviendo un objeto anónimo, ¿cómo lo devuelvo desde mi repositorio para poder construir el ViewModel en las acciones de mi controlador?


Está correcto que un repositorio no debería devolver un modelo de vista. Como los cambios en su vista le harán cambiar su capa de datos.

Su repositorio debe ser una raíz agregada . Si su propiedad1, propiedad2, Foo, Bar están relacionadas de alguna manera, extraería una nueva clase para manejar esto.

public class FooBarDetails { public string Property1 {get;set;} public string Property2 {get;set;} public Foo Foo {get;set;} public Bar Bar {get;set;} } var details = _repo.GetDetails(detailId);

Si Foo y Bar no están relacionados en absoluto, podría ser una opción para introducir un servicio para componer sus FooBarDetails.

FooBarDetails details = _service.GetFooBar(id);

donde GetFooBar(int) se vería algo así:

_fooRepo.Get(id); _barRepo.Get(id); return new FooBarDetails{Foo = foo, Bar = bar, Property1 = "something", Property2 = "something else"};

Todo esto es una conjetura ya que el diseño del repositorio realmente depende de su dominio. El uso de términos genéricos hace que sea difícil desarrollar relaciones potenciales entre sus objetos.

Actualizado desde el comentario si estamos tratando con una raíz agregada de una Orden. Un pedido tendría el artículo de pedido y también el cliente que realizó el pedido.

public class Order { public List<OrderItem> Items{get; private set;} public Customer OrderedBy {get; private set;} //Other stuff } public class Customer { public List<Orders> Orders{get;set;} }

Su repo debe devolver un objeto de pedido completamente hidratado.

var order = _rep.Get(orderId);

Dado que su pedido tiene toda la información necesaria, pasaría el pedido directamente al modelo de vista.

public class OrderDetailsViewModel { public Order Order {get;set;} public OrderDetailsViewModel(Order order) { Order = order; } }

Ahora, tener un modelo de vista con un solo elemento puede parecer excesivo (y es muy probable que lo sea al principio). Si necesita mostrar más elementos en su vista, comienza a ayudar.

public class OrderDetailsViewModel { public Order Order {get;set;} public List<Order> SimilarOrders {get;set;} public OrderDetailsViewModel(Order order, List<Order> similarOrders) { Order = order; SimilarOrders = similarOrders; } }


Las respuestas actuales son muy buenas. Simplemente señalaría que está abusando de tipos anónimos; solo deben usarse para pasos de transporte intermedios, y nunca deben pasarse a otros lugares en su código (por ejemplo, ver constructores de modelos).

Mi enfoque sería inyectar el modelo de vista con todas las clases de modelos relevantes. Por ejemplo, un método de acción podría ser:

var dinner = dinnerRepository.Get(dinnerId); var bar = barRepository.Get(barId); var viewModel = new DinnerAndBarFormViewModel(dinner, bar); return View(viewModel);


Si bien la mayoría de las respuestas son buenas, creo que faltan una parte de las líneas de su pregunta.

En primer lugar, no hay una forma 100% correcta de hacerlo, y aún no me habría colgado los detalles del patrón exacto para usar. A medida que su aplicación se desarrolle más y más, comenzará a ver qué funciona y qué no, y encontrará la mejor manera de cambiarla para que funcione para usted y para su aplicación. Acabo de terminar de cambiar completamente el patrón de mi backend Asp.Net MVC, principalmente porque muchos de los consejos que encontré no funcionaban para lo que estaba tratando de hacer.

Dicho esto, mira tus capas por lo que se supone que deben hacer. La capa de repositorio está destinada únicamente para agregar / eliminar / editar datos de su origen de datos. No sabe cómo se van a utilizar esos datos y, francamente, no les importa. Por lo tanto, los repositorios deberían devolver sus entidades EF.

La parte de su pregunta que otros parecen faltar es que necesita una capa adicional entre sus controladores y los repositorios, generalmente llamada capa de servicio o capa de negocios. Esta capa contiene varias clases (sin embargo, usted quiere organizarlas) a las que los controladores invocan. Cada una de estas clases llamará al repositorio para recuperar los datos deseados y luego los convertirá en los modelos de vista que sus controladores terminarán utilizando.

Esta capa de servicio / negocio es donde va su lógica de negocios (y si lo piensa, convertir una entidad en un modelo de vista es la lógica de negocios, ya que define cómo su aplicación realmente va a usar esos datos). Esto significa que no tienes que llamar a métodos de conversión específicos ni a nada. La idea es que le diga a su capa de servicio / negocio lo que quiere hacer, y le devuelve las entidades comerciales (modelos de vista), y sus controladores no tienen conocimiento de la estructura real de la base de datos ni de cómo se recuperaron los datos.

La capa de servicio debería ser la única capa que también llame a las clases de repositorio.


Tengo la misma duda del cartel y todavía no estoy convencido. Personalmente, no me gusta mucho el consejo dado de limitar el repositorio a solo ejecutar las operaciones básicas de CRUD. En mi humilde opinión, las actuaciones siempre deben tenerse en cuenta al desarrollar una aplicación real, y la sustitución de una combinación externa SQL con dos consultas diferentes para las relaciones maestro-detalle no me parece demasiado buena. Además, de esta manera, se pierde por completo el principio de que solo se deben consultar los campos necesarios: al usar este enfoque, nos vemos obligados a recuperar todos los campos de todas las tablas involucradas, ¡lo cual es una locura en aplicaciones que no son juguetes!