Get Products

كنا عملنا في الـ Specification Design Pattern

  • محتاج أستخدمها مع الـ GetAllWithSpecAsync بس هي بتحتاج تاخد spec
  • فهنحتاج نعمل object من الـ class اللي اسمه BaseSpecifications
public async Task<ActionResult<IEnumerable<Product>>> GetProducts()
{
	var spec = new BaseSpecifications<Product>();
	var products = await _productsRepo.GetAllWithSpecAsync(spec);
 
	return Ok(products)
}

نروح على Postman ونشوف الـ Collection اللي اسمه Session 02 ونغير الـ Variable بتاع الـ URL


هنلاقي فيه مشكلة ان دلوقتي بينادي على Specification والـ Criteria بـ Null ودا عادي بس المشكلة في الـ Includes هنلاقي ان الـ List فاضية وهنا المشكلة لأن المفروض يبقا فيها اتنين واحد للـ Brand وواحد للـ Category

فحل ممكن نعمله اننا نروح للـ ctor الفاضي ونضيف بايدينا الـ Expression

public BaseSpecification()
{
	Includes.Add(P => P.Brand);
}

بس هيظهرلنا لأنه ميعرفش ايه الـ P دا لأننا عاملينها Generic فهو من النوع T وممكن الـ T تبقا أي حاجة من الـ Base Entity مش شرط Product ودا منطقي عشان لو حبينا نستخدمها مع باقي الحاجات


الحل

  • هنعمل في الـ Core نعمل فولدر اسمه Specifications
  • ونعمل للـ Product فولدر خاص بيه نسميه ProductSpecs
  • ونعمل Class نسميه ProductWithBrandAndCategorySpecifications
  • هيكون Public
  • هيورث من الـ BaseSpecifications فهاخد منه الـ Properties
  • والـ Empty Ctor اللي هو هيعمل Chaining من الـ Empty بتاع الـ Base
  • احنا جواه بقا نحط الـ Includes بتاعنا
public class ProductWithBrandAndCategorySpecifications : BaseSpecifications<Product>
{
	public ProductWithBrandAndCategorySpecifications()
		:base()
	{
		Includes.Add(P => P.Brand);
		Includes.Add(P => P.Category);
	}
}
  • الـ Ctor دا هنستخدمه عشان GetAll
  • طيب لما هندخل على الـ Generic Repository ونشوف الـ GetAllWithSpecAsync فالسؤال المهم هو اتحدد امتا ان الـ T هو الـ Product؟ الإجابة هتكون هو من خلال الـ Ctor بتاع الـ Generic Repository اللي اتعمل في الـ Controller وكنا عملناه Ctor Injection فاتحدد من وقتها

في الآخر خالص هنستخدم الـ Spec المخصصة لـ Product دي في الـ Endpoint نفسها اللي هي GetAllWithSpecAsync

Get Product by ID

  • هنروح في الـ Endpoint بتاعها ونستخدم الـ GetWithSpecAsync
  • هيقولي برضو انه محتاج spec فهنعمل Object منه ومحتاج نبعتله الـ ID
var spec = new ProductWithBrandAndCategorySpecifications(id);
var product = await _productRepo.GetWithSpecAsync();
  • بس معنديش ctor بياخد Id فهحتاج أعمل واحد بياخد Id
  • والفرق هنا انها مش هتعمل Chaining من Empty ctor انما هتعمل على اللي له Criteria عن طريق اني أمررلها الـ Expression بتاعتنا
public ProductWithBrandAndCategorySpecifications(int id)
	:base(P => P.Id == id)
{
	Includes.Add(P => P.Brand);
	Includes.Add(P => P.Category);
}

ممكن السطرين بتوع الـ Includes دول بيتكرروا فنخليهم في Method عشان احنا مبنحبش التكرار ونسميها AddIncludes

شغل كل واحدة منهم واعمل Breakpoint على أول الـ Endpoint وتابع البروجكت وهو شغال