IEnumerable VS IQueryable
IEnumerable<T>
is an interface in the System.Collections.Generic namespace, used for iterating
over a collection of objects one at a time.
It operates
with deferred execution for in-memory collections, meaning the query is
executed after the data is fetched.
Commonly used
with in-memory collections like lists or arrays, and in LINQ-to-Objects
queries.
Operations
like Where, Select, and OrderBy are applied in memory once the collection is
loaded.
Not ideal for
large datasets, as it loads the entire collection into memory, which may cause
performance issues.
IEnumerable<T>
is commonly used for:
Filtering and
Transforming Data: Modifying in-memory collections (e.g., filtering products or
transforming strings with LINQ).
Sorting and
Paging: Sorting and paginating in-memory datasets (e.g., displaying user data
with pagination).
Aggregation:
Performing calculations like Sum, Count, or Average on small datasets (e.g.,
calculating total revenue from orders).
Data
Transformation: Applying changes to data, such as trimming or formatting (e.g.,
transforming customer names).
Example:
using System;
using
System.Collections.Generic;
using
System.Linq;
namespace
IEnumerableExample
{
// Example Product class
public class Product
{
public string Name { get; set; }
public decimal Price { get; set; }
public bool InStock { get; set; }
}
// Example Order class
public class Order
{
public int OrderId { get; set; }
public decimal Amount { get; set; }
public DateTime OrderDate { get; set; }
}
// Example Customer class
public class Customer
{
public string Name { get; set; }
public string Email { get; set; }
}
class Program
{
static void Main(string[] args)
{
// Sample data
List<Product> products = new
List<Product>
{
new Product { Name =
"Laptop", Price = 1000, InStock = true },
new Product { Name =
"Smartphone", Price = 500, InStock = false },
new Product { Name =
"Tablet", Price = 300, InStock = true },
new Product { Name =
"Headphones", Price = 150, InStock = true }
};
List<Order> orders = new List<Order>
{
new Order { OrderId = 1, Amount =
1500, OrderDate = DateTime.Now.AddDays(-10) },
new Order { OrderId = 2, Amount =
250, OrderDate = DateTime.Now.AddDays(-5) },
new Order { OrderId = 3, Amount =
800, OrderDate = DateTime.Now.AddDays(-2) }
};
List<Customer> customers = new
List<Customer>
{
new Customer { Name = "John
Doe", Email = "john.doe@example.com" },
new Customer { Name = "Jane
Smith", Email = "jane.smith@example.com" },
new Customer { Name = "Alice
Johnson", Email = "alice.johnson@example.com" }
};
// 1. Filtering and Transforming Data: Filtering
products in stock and applying a discount
var inStockProducts = products
.Where(p => p.InStock)
.Select(p => new { p.Name,
DiscountedPrice = p.Price * 0.9m }) // Apply 10% discount
.ToList();
Console.WriteLine("In Stock Products with
Discount:");
foreach (var product in inStockProducts)
{
Console.WriteLine($"{product.Name} - Discounted Price:
{product.DiscountedPrice:C}");
}
Console.WriteLine();
// 2. Sorting and Paging: Sorting products by price
and paginating (Page 1, 2 items per page)
int page = 1;
int pageSize = 2;
var pagedProducts = products
.OrderBy(p => p.Price) //
Sort by price
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToList();
Console.WriteLine($"Paged Products (Page
{page}):");
foreach (var product in pagedProducts)
{
Console.WriteLine($"{product.Name}
- Price: {product.Price:C}");
}
Console.WriteLine();
// 3. Aggregation: Calculate the total revenue from
orders
decimal totalRevenue = orders.Sum(o =>
o.Amount);
Console.WriteLine($"Total Revenue:
{totalRevenue:C}");
Console.WriteLine();
// 4. Data Transformation: Trimming and formatting
customer names
var formattedCustomerNames = customers
.Select(c => new { FormattedName =
c.Name.Trim().ToUpper() })
.ToList();
Console.WriteLine("Formatted Customer
Names:");
foreach (var customer in formattedCustomerNames)
{
Console.WriteLine(customer.FormattedName);
}
}
}
}
IQueryable<T>
is an interface in the System.Linq namespace, used for querying collections in
a flexible way, often with remote data sources like databases or web APIs.
It allows
queries to be translated into a query language (e.g., SQL) and executed on the
data source, optimizing performance on the source (e.g., SQL Server, MongoDB).
Typically
used for querying external data sources, such as databases, and in scenarios
like LINQ-to-Entities or LINQ-to-SQL, where queries are constructed to be
translated into SQL.
Operations
like Where, Select, and OrderBy are applied in the query expression and
executed on the data source (e.g., database query).
More
efficient for large datasets, as it allows filtering, ordering, and pagination
to be performed at the data source level before data is fetched into memory.
Summary of
Concepts:
Querying
Large Data Sources: Efficiently fetches large datasets from external sources
like databases by letting the data source handle operations such as filtering,
sorting, and pagination.
Remote Data
Querying: Ideal for querying remote data sources (e.g., APIs), applying
operations server-side to minimize data transfer.
Complex Query
Logic: Supports building complex queries, like joins, groupings, and
aggregations, which can be translated into optimized SQL queries.
Dynamic
Queries: Allows building queries dynamically based on runtime conditions,
without needing to load the entire dataset into memory.
Pagination:
Efficiently handles large datasets by implementing pagination with Skip and
Take to fetch only necessary data.
Optimized for
Scalability: Ensures scalability by executing query logic on the database or
external system, improving performance and reducing memory usage.
public async
Task<IActionResult> GetFilteredProducts(int page, int pageSize, string?
nameFilter, decimal? minPrice, string? sortBy)
{
IQueryable<Product> query = _dbContext.Products;
// Apply dynamic filters based on user input
if (!string.IsNullOrEmpty(nameFilter))
{
query = query.Where(p => p.Name.Contains(nameFilter));
}
if (minPrice.HasValue)
{
query = query.Where(p => p.Price >= minPrice.Value);
}
// Complex query logic: Join with Category table to filter by category
query = query.Join(_dbContext.Categories, p => p.CategoryId, c => c.Id,
(p, c) => new { p, c })
.Where(pc => pc.c.IsActive);
// Apply sorting based on user input
if (sortBy == "Price")
{
query = query.OrderBy(pc => pc.p.Price);
}
else if (sortBy == "Name")
{
query = query.OrderBy(pc => pc.p.Name);
}
else
{
query = query.OrderBy(pc => pc.p.CreatedDate); //
Default sorting
}
// Implement pagination: Skip and Take are executed at the database level
var pagedProducts = query.Skip((page - 1) * pageSize).Take(pageSize);
// Execute query on the database
var result = await pagedProducts.ToListAsync();
// Count total filtered records for pagination info
var totalCount = await query.CountAsync();
// Return the paginated and filtered data along with total count
return Ok(new
{
Items = result,
TotalCount = totalCount
});
}
IEnumerable<T>
is part of the System.Collections.Generic namespace, while IQueryable<T>
is part of the System.Linq namespace.
IEnumerable<T>
executes queries in-memory after the data is fetched, applying operations like
Where and Select on the loaded collection. In contrast, IQueryable<T>
executes queries on the data source (e.g., SQL database), translating the query
into a query language like SQL for optimization at the source.
IEnumerable<T>
is typically used for in-memory collections like lists or arrays, and is
commonly used with LINQ-to-Objects. IQueryable<T> is used for querying
external data sources like databases and is used in scenarios such as
LINQ-to-Entities or LINQ-to-SQL.
With
IEnumerable<T>, operations like Where, Select, and OrderBy are applied
in-memory once the collection is loaded. For IQueryable<T>, these
operations are applied in the query expression and executed on the data source
(e.g., as SQL queries).
IEnumerable<T>
can be inefficient for large datasets because it loads the entire collection
into memory, which may cause performance issues. IQueryable<T> is more
efficient for large datasets, as filtering, ordering, and pagination are
performed at the data source level before the data is fetched into memory.
Comments
Post a Comment