C#에서 IQueryable과 IEnumerable은 LINQ 쿼리를 실행하기 위해 사용되는 두 가지 인터페이스입니다. 이 두 인터페이스는 데이터 소스로부터 데이터를 쿼리하는 방법에 따라 다르게 작동합니다.
IEnumerable은 .NET Framework에서 가장 일반적으로 사용되는 인터페이스 중 하나입니다. 이 인터페이스는 컬렉션의 모든 항목을 반복하고 각 항목에 대한 단순한 foreach 루프를 제공합니다. IEnumerable은 일반적으로 메모리 내 컬렉션에서 사용됩니다. IEnumerable은 모든 데이터를 메모리로 가져와서 필터링, 정렬 및 기타 작업을 수행합니다. 따라서 대량의 데이터 집합에서 작업하는 경우 많은 메모리를 소비하고 성능에 영향을 미칠 수 있습니다.
IEnumerable은 Loop 를 사용하여 데이터 소스에서 순차적으로 데이터를 검색합니다. IEnumerable은 데이터를 메모리에 미리로드하여 쿼리를 수행하므로 쿼리 수행 시 모든 데이터를 가져오기 때문에 메모리 사용량이 높아질 수 있습니다. 이러한 이유로 IEnumerable은 작은 데이터셋에서 사용할 때 유용합니다.
IQueryable은 IEnumerable와 매우 유사하지만 더 많은 유연성을 제공합니다. LINQ 쿼리를 빌드하고 데이터베이스와 같은 외부 데이터 소스에 대한 쿼리를 빌드하기 위한 인터페이스입니다. IQueryable은 일반적으로 데이터 소스에서 직접 작업을 수행합니다. 이는 데이터베이스, 웹 서비스 또는 기타 데이터 원본과 같은 데이터 저장소에서 데이터를 검색하는 경우 특히 유용합니다. 또한 LINQ(언어 통합 쿼리)를 사용하여 데이터 원본에서 쿼리를 실행할 수 있습니다. LINQ는 IQueryable과 함께 사용될 때 쿼리를 최적화하고 데이터베이스 쿼리의 일부로 변환하는 기능을 제공합니다. 이는 대량의 데이터를 처리할 때 성능과 메모리 사용량을 최적화할 수 있는 장점을 제공합니다.
즉, IQueryable은 쿼리를 구성한 후에도 데이터 소스로부터 데이터를 검색하지 않습니다. 대신, 데이터 소스에 대한 쿼리를 작성하고 데이터를 검색하기 위한 적절한 메서드를 호출하여 데이터를 가져옵니다. 이 방법은 데이터베이스와 같은 대규모 데이터셋에서 쿼리를 수행할 때 효율적입니다.
다음은 IQueryable과 IEnumerable의 예제입니다.
IEnumerable
var list = new List<int> { 1, 2, 3, 4, 5 };
var query = from i in list
where i > 3
select i;
foreach (var item in query)
{
Console.WriteLine(item);
}
IQueryable
var dbContext = new MyDbContext();
var query = from c in dbContext.Customers
where c.City == "New York"
select c;
foreach (var item in query)
{
Console.WriteLine(item.Name);
}
위 예제에서, IEnumerable은 메모리에서 데이터를 가져오므로 작은 데이터셋에서 사용할 때 유용합니다. IQueryable은 데이터베이스와 같은 대규모 데이터셋에서 쿼리를 수행할 때 효율적입니다.
IQueryable은 IQueryable<T> 인터페이스를 사용하여 정의됩니다. 따라서 IQueryable을 사용하려면 데이터 소스에 대한 IQueryable<T> 인터페이스를 구현해야 합니다.
public class ProductRepository : IQueryable<Product>
{
private readonly DbContext dbContext;
public ProductRepository(DbContext dbContext)
{
this.dbContext = dbContext;
}
public IEnumerator<Product> GetEnumerator()
{
return dbContext.Products.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public Type ElementType => typeof(Product);
public Expression Expression => dbContext.Products.Expression;
public IQueryProvider Provider => dbContext.Products.Provider;
}
위 예제는 Product 데이터 소스에 대한 ProductRepository 클래스를 구현하는 방법을 보여줍니다. ProductRepository 클래스는 IQueryable<Product> 인터페이스를 구현하므로 IQueryable을 사용하여 Product 데이터를 검색할 수 있습니다.
var repository = new ProductRepository(dbContext);
var query = from p in repository
where p.Category == "Books"
select p;
foreach (var product in query)
{
Console.WriteLine(product.Name);
}
이 예제에서는 Product 데이터 소스에 대한 IQueryable<T> 인터페이스를 구현하는 방법을 보여주며 IQueryable을 사용하여 데이터를 검색하는 방법을 보여줍니다.
IEnumerable과 IQueryable은 모두 C#에서 데이터를 검색하고 조작하는 데 사용됩니다. 하지만 두 인터페이스는 목적과 사용 방법에 차이가 있습니다. IEnumerable은 일반적으로 메모리 내 컬렉션에서 사용되며 IQueryable은 데이터베이스, 웹 서비스 또는 기타 데이터 원본과 같은 데이터 저장소에서 데이터를 검색하는 경우 특히 유용합니다.
따라서 데이터 검색에 대한 작업을 수행할 때 해당 데이터 소스의 특성에 따라 적절한 인터페이스를 선택하고 적절한 방법으로 사용하는 것이 중요합니다.
페이징 처리
페이징 처리는 Count() 메소드를 사용하여 전체 데이터의 수를 가져온 후, Skip() 및 Take() 메소드를 사용하여 특정 페이지의 항목을 가져옵니다. 이를 ToList() 메소드를 사용하여 최종 결과를 가져옵니다.
using System;
using System.Linq;
class Program
{
static void Main(string[] args)
{
using (var db = new NorthwindEntities())
{
int pageSize = 10;
int pageNumber = 3;
var query = db.Orders.OrderBy(o => o.OrderDate);
int totalCount = query.Count();
var orders = query.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList();
Console.WriteLine("Page {0} of {1}", pageNumber, Math.Ceiling((double)totalCount / pageSize));
foreach (var order in orders)
{
Console.WriteLine("{0} - {1}", order.OrderID, order.OrderDate);
}
}
}
}