LINQ en ASP.NET MVC: Consultas avanzadas con Join y GroupBy

En el desarrollo de aplicaciones web utilizando ASP.NET MVC junto con Entity Framework, las consultas avanzadas con LINQ (Language Integrated Query) son esenciales para manipular y presentar datos de manera eficiente. En este artículo, exploraremos cómo utilizar LINQ con las operaciones de GroupBy y Join para crear un reporte de ventas agrupado por producto. Este ejemplo práctico te proporcionará una comprensión clara de cómo estructurar y utilizar consultas avanzadas en tus proyectos ASP.NET MVC.

Creación del Proyecto en Visual Studio

Para comenzar, abre Visual Studio y sigue los pasos a continuación:

  1. Crear un Nuevo Proyecto:

    • Ve a File > New > Project en Visual Studio.
    • Selecciona ASP.NET Web Application como tipo de proyecto.
    • Asigna un nombre al proyecto, por ejemplo, SalesReportApp.
    • Selecciona MVC como plantilla de proyecto.
  2. Instalación de Entity Framework:

    • Abre Package Manager Console desde Tools > NuGet Package Manager > Package Manager Console.
    • Ejecuta el siguiente comando para instalar Entity Framework:
Install-Package EntityFramework

 

 

Definición de los Modelos de Datos

En la carpeta Models de tu proyecto, define los modelos Product, Order y OrderDetail que representan las entidades principales involucradas en el ejemplo de reporte de ventas.

Product.cs:

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}

Order.cs:

public class Order
{
    public int Id { get; set; }
    public DateTime OrderDate { get; set; }
    public ICollection<OrderDetail> OrderDetails { get; set; }
}

OrderDetail.cs:

public class OrderDetail
{
    public int Id { get; set; }
    public int OrderId { get; set; }
    public int ProductId { get; set; }
    public int Quantity { get; set; }
    public Order Order { get; set; }
    public Product Product { get; set; }
}

 

Definición de SalesReportViewModel

Crea una clase SalesReportViewModel en la carpeta Models para representar los datos que se mostrarán en la vista del reporte de ventas.

SalesReportViewModel.cs:

public class SalesReportViewModel
{
    public string ProductName { get; set; }
    public decimal TotalSales { get; set; }
}

 

 

Configuración del Contexto de Datos

Crea una clase ApplicationDbContext que extienda DbContext para configurar la conexión y las relaciones entre las tablas de la base de datos utilizando Entity Framework.

 

ApplicationDbContext.cs:

using System.Data.Entity;

public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext() : base("name=ApplicationDbContext")
    {
    }

    public DbSet<Product> Products { get; set; }
    public DbSet<Order> Orders { get; set; }
    public DbSet<OrderDetail> OrderDetails { get; set; }
}

 

Configuración de la Cadena de Conexión

Abre el archivo Web.config y añade la cadena de conexión dentro de <configuration><connectionStrings>:

<connectionStrings>
    <add name="ApplicationDbContext" 
         connectionString="Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=SalesReportDb;Integrated Security=True" 
         providerName="System.Data.SqlClient" />
</connectionStrings>

 

 

Poblar la Simulación de Base de Datos

Para simular datos de prueba en la base de datos, vamos a usar el método Seed en la clase de configuración de migraciones para insertar algunos productos y órdenes de ejemplo.

Configuration.cs (en la carpeta Migrations):

using System;
using System.Collections.Generic;
using System.Data.Entity.Migrations;
using System.Linq;
using YourNamespace.Models;

internal sealed class Configuration : DbMigrationsConfiguration<ApplicationDbContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
    }

    protected override void Seed(ApplicationDbContext context)
    {
        var products = new List<Product>
        {
            new Product { Name = "Product A", Price = 100 },
            new Product { Name = "Product B", Price = 150 },
            new Product { Name = "Product C", Price = 75 }
        };
        products.ForEach(p => context.Products.AddOrUpdate(x => x.Name, p));
        context.SaveChanges();

        var orders = new List<Order>
        {
            new Order { OrderDate = DateTime.Now.AddDays(-10), OrderDetails = new List<OrderDetail>
                {
                    new OrderDetail { ProductId = 1, Quantity = 2 },
                    new OrderDetail { ProductId = 2, Quantity = 1 }
                }
            },
            new Order { OrderDate = DateTime.Now.AddDays(-5), OrderDetails = new List<OrderDetail>
                {
                    new OrderDetail { ProductId = 1, Quantity = 3 },
                    new OrderDetail { ProductId = 3, Quantity = 2 }
                }
            },
            new Order { OrderDate = DateTime.Now.AddDays(-2), OrderDetails = new List<OrderDetail>
                {
                    new OrderDetail { ProductId = 2, Quantity = 2 }
                }
            }
        };
        orders.ForEach(o => context.Orders.AddOrUpdate(x => x.OrderDate, o));
        context.SaveChanges();
    }
}

Explicación:

  • Clase Configuration: Esta clase se utiliza para configurar y poblar la base de datos utilizando migraciones de Entity Framework.

  • Método Seed: El método Seed se sobrescribe para proporcionar datos de prueba (Seed) a la base de datos. Aquí se crean y agregan varios productos (Product) y órdenes (Order) con detalles de órdenes (OrderDetail).

  • Operaciones AddOrUpdate: Estas operaciones aseguran que los registros no se dupliquen en la base de datos si ya existen registros con el mismo identificador único (x => x.Name para Product y x => x.OrderDate para Order).

 

 

Implementación del Controlador y Consulta LINQ

En el controlador ReportsController, implementaremos la acción SalesReport que realizará consultas personalizadas utilizando LINQ con GroupBy y Join para calcular y agrupar las ventas por producto.

using System.Linq;
using System.Web.Mvc;
using YourNamespace.Models;

public class ReportsController : Controller
{
    private ApplicationDbContext db = new ApplicationDbContext();

    public ActionResult SalesReport()
    {
        var sales = from o in db.Orders
                    join od in db.OrderDetails on o.Id equals od.OrderId
                    join p in db.Products on od.ProductId equals p.Id
                    group new { od, p } by p.Name into g
                    select new SalesReportViewModel
                    {
                        ProductName = g.Key,
                        TotalSales = g.Sum(x => x.od.Quantity * x.p.Price)
                    };

        return View(sales.ToList());
    }
}

 

Explicación Detallada del Código LINQ

1. Join entre Tablas: Unimos las tablas Orders, OrderDetails y Products para obtener la información necesaria de cada pedido y producto.

join od in db.OrderDetails on o.Id equals od.OrderId
join p in db.Products on od.ProductId equals p.Id

Aquí, estamos uniendo las tablas OrderDetails y Products a través de las claves foráneas (OrderId y ProductId respectivamente) con sus entidades padre (Order y Product).

 

2. Agrupación por Producto: Agrupamos los resultados por el nombre del producto (p.Name) usando GroupBy.

group new { od, p } by p.Name into g

new { od, p } crea un objeto anónimo que contiene los detalles de la orden (OrderDetail) y el producto (Product) para cada registro.

g es la variable de agrupación que contiene los elementos agrupados por el nombre del producto.

 

3. Cálculo de Total de Ventas: Calculamos el total de ventas para cada producto sumando la cantidad (od.Quantity) multiplicada por el precio (p.Price) de cada producto en la orden.

TotalSales = g.Sum(x => x.od.Quantity * x.p.Price)

Utilizamos la función de agregación Sum de LINQ para calcular la suma total de las ventas para cada grupo g.

 

4. Proyección de Resultados: Proyectamos los resultados agrupados en un nuevo objeto SalesReportViewModel, que contiene el nombre del producto y el total de ventas calculado.

select new SalesReportViewModel
{
    ProductName = g.Key,
    TotalSales = g.Sum(x => x.od.Quantity * x.p.Price)
}

select new SalesReportViewModel crea una nueva instancia de SalesReportViewModel para cada grupo g.

g.Key representa la clave por la cual se agruparon los datos, es decir, el nombre del producto.

g.Sum(x => x.od.Quantity * x.p.Price) calcula la suma total de las ventas multiplicando la cantidad de cada producto por su precio.

 

 

Vista y Presentación de Resultados

Crea una vista SalesReport.cshtml en la carpeta Views/Reports para mostrar el reporte de ventas.

@model IEnumerable<SalesReportApp.Models.SalesReportViewModel>

<h2>Sales Report</h2>

<table class="table">
    <thead>
        <tr>
            <th>Product Name</th>
            <th>Total Sales</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model)
        {
            <tr>
                <td>@item.ProductName</td>
                <td>@item.TotalSales.ToString("C")</td>
            </tr>
        }
    </tbody>
</table>

Explicación:

  • Modelo: La vista está fuertemente tipada con IEnumerable<SalesReportViewModel>, donde SalesReportViewModel tiene propiedades ProductName y TotalSales.

  • Tabla HTML: Se utiliza una tabla HTML para mostrar los resultados de manera tabular.

    • <thead> contiene las cabeceras de las columnas: "Product Name" y "Total Sales".

    • <tbody> contiene las filas generadas dinámicamente con datos de cada producto y su total de ventas.

    • @foreach itera sobre cada elemento del modelo (SalesReportViewModel) para mostrar cada producto y su total de ventas en la tabla.

    • @item.ProductName muestra el nombre del producto.

    • @item.TotalSales.ToString("C") muestra el total de ventas formateado como moneda.

 

 

Conclusiónes

En este artículo, hemos explorado cómo utilizar LINQ con las operaciones GroupBy y Join en ASP.NET MVC para generar un reporte de ventas agrupado por producto. Estas técnicas son fundamentales para manejar datos complejos y ofrecen una gran flexibilidad para la manipulación y presentación de información en aplicaciones web. Al dominar estas herramientas, puedes construir aplicaciones más eficientes y con mejores capacidades analíticas, mejorando así la experiencia del usuario y optimizando la gestión de datos en tus proyectos.

Con esto, tienes una base sólida para explorar y aplicar LINQ en tus propios proyectos ASP.NET MVC, aprovechando al máximo las capacidades de Entity Framework para acceder y manipular datos de manera eficiente.

 

   EtiquetasASP.NET MVC LINQ Entity Framework

  Compartir


  Nuevo comentario

El campo Comentario es obligatorio.
El campo Nombre es obligatorio.

  Comentarios

No hay comentarios para este Post.



Utilizamos cookies propias y de terceros para mejorar nuestros servicios y ofrecerle una mejor experiencia de navegación. Si continúa navegando consideramos que acepta su uso. Más información   Acepto