آشنایی با الگوی مخزن نشتیدار در برنامهنویسی #C و روشهای رفع آن
نویسنده: وحید نصیری
تاریخ: ۱۴۰۴/۰۱/۲۱ ۰۷:۱۸
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
IQueryable<T> از متدهای مخزن است. این کار به ظاهر انعطافپذیری بالایی به مصرفکنندگان میدهد، اما در عمل جزئیات پیادهسازی را افشا میکند. به عنوان مثال:public interface IProductRepository
{
IQueryable<Product> GetProducts();
}
public class ProductRepository : IProductRepository
{
private readonly DbContext _context;
public ProductRepository(DbContext context)
{
_context = context;
}
public IQueryable<Product> GetProducts()
{
return _context.Products;
}
}var discountedProducts = repository.GetProducts()
.Where(p => p.Category == "EBooks")
.Where(p => p.Price > 100)
.OrderBy(p => p.Name)
.Skip(100)
.Take(10)
.ToList();public interface IRepository<T> where T : class
{
DbSet<T> Entities { get; }
void Attach(T entity);
void DetachEntity(T entity);
EntityEntry<T> GetEntityEntry(T entity);
}public Customer GetById(int id)
{
try
{
return _context.Customers.Find(id);
}
catch (SqlException ex)
{
throw;
}
}SqlException که خاص SQL Server است، به لایه بالاتر نشت میکند و مصرفکننده را مجبور به وابستگی به جزئیات پایگاه داده میکند.public class OrderRepository : IOrderRepository
{
private readonly DbContext _context;
public Order GetById(int id)
{
return _context.Orders.Find(id);
}
}
var order = orderRepository.GetById(1111);
foreach (var item in order.OrderItems)
{
// ممکن است کوئریهای اضافی اجرا شود
}public interface IProductRepository
{
IReadOnlyCollection<Product> GetProductsByCategory(string category);
IReadOnlyCollection<Product> GetDiscountedProducts(decimal minPrice);
PagedResult<Product> GetProductsPaged(int page, int pageSize, string sortField);
}public interface ISpecification<T>
{
Expression<Func<T, bool>> Criteria { get; }
List<Expression<Func<T, object>>> Includes { get; }
Expression<Func<T, object>> OrderBy { get; }
int Take { get; }
int Skip { get; }
}
public interface IRepository<T>
{
IReadOnlyList<T> FindAll(ISpecification<T> spec);
}
public class DiscountedEbooksSpecification : BaseSpecification<Product>
{
public DiscountedEbooksSpecification(decimal minPrice)
: base(p => p.Category == "Ebooks" && p.Price > minPrice)
{
AddOrderBy(p => p.Name);
ApplyPaging(10, 10);
}
}
var spec = new DiscountedEbooksSpecification(69);
var products = repository.FindAll(spec);public class EntityNotFoundException : Exception
{
public EntityNotFoundException(string entityType, object key)
: base($"{entityType} با شناسه {key} یافت نشد.")
{
}
}
public Customer GetById(int id)
{
try
{
var customer = _context.Customers.Find(id);
if (customer == null)
throw new EntityNotFoundException("Customer", id);
return customer;
}
catch (SqlException ex)
{
throw new Exception("خطا در دسترسی به دادهها", ex);
}
}public Order GetOrderWithDetails(int id)
{
return _context.Orders
.Include(o => o.OrderItems)
.ThenInclude(i => i.Product)
.FirstOrDefault(o => o.Id == id);
}public OrderDetailsDto GetOrderDetails(int id)
{
return _context.Orders
.Where(o => o.Id == id)
.Select(o => new OrderDetailsDto
{
OrderId = o.Id,
CustomerName = o.Customer.Name,
Items = o.OrderItems.Select(i => new OrderItemDto
{
ProductName = i.Product.Name,
Quantity = i.Quantity
}).ToList()
})
.FirstOrDefault();
}IQueryable renormalization، استفاده از الگوی مشخصات برای کوئریهای پیچیده، مدیریت صحیح استثناها و بهکارگیری بارگذاری مشتاق یا پروجکشن، میتوان مخزنهایی طراحی کرد که واقعاً به وعدههای خود عمل کنند. این اصول به توسعهدهندگان کمک میکند تا کدهایی تمیز، قابل نگهداری و مستقل از فناوری بنویسند که در بلندمدت ارزش خود را حفظ کنند.