tgoop.com/fullStackDevs/446
Create:
Last Update:
Last Update:
ادامه پست قبل :
🌀 Specification pattern
نحوه استفاده از آن
// Controller🔹 اما در این روش هم باز همان مشکل قبل را داریم و کلاس جنریک specification در اینجا فقط به عنوان یک wrapper برروی expression قبلی مان عمل میکند پس نتیجه ای که میتوانیم بگیریم این است که GenericSpecification یک روش بد میباشد.چون فقط نقش یک Container را ایفا میکند که Client ها به اطلاعات خود را پاس میدهند و مشکل کپسوله سازی اطلاعات دامین مدل ها هنوز پا برجا و حل نشده باقی مانده است.
public void SomeMethod()
{
var specification = new GenericSpecification<Movie>(
m => m.MpaaRating == MpaaRating.G);
var movies = _repository.Find(specification); // Getting a list of movies
}
// Repository
public IReadOnlyList<Movie> Find(GenericSpecification<Movie> specification)
{
return db
.Where(specification.Expression)
.ToList();
}
✔️ اما راهکار چیست؟
🔳 راه حل درست، استفاده از پیاده سازی ای از الگو specification تحت عنوان Strongly-typed specifications میباشد.
در این روش الگوی specification طوری پیاده سازی شده است که در آن اطلاعات دامین مدل نوشته شده و با کمترین امکان تغییر از خارج از کلاس پیاده سازی کننده پیاده سازی شده است. نحوه پیاده سازی :
public abstract class Specification<T>🔸 در این روش باید به ازای هر شاخص یا عملگری که میخواهید به عنوان یک فیلتر بر روی DbSet انجام شود،باید کلاسی تعریف کنید که از ابستراکت کلاس Specification<T> ارث بری کرده و متد ToExpression() انرا override و پیاده سازی کند. مثلا در مثال بالا ما به ازای شاخص MpaaRating که یک enum در کلاس Movie بود .یک کلاس با نام MpaaRatingAtMostSpecification ایجاد کردیم که از ابستراکت کلاس Specification<T> ارث بری کرده و با override کردن ToExpression() و پیاده سازی آن به صورت :
{
public abstract Expression<Func<T , bool>> ToExpression();
public bool IsSatisfiedBy(T entity)
{
Func<T , bool> predicate = ToExpression().Compile();
return predicate(entity);
}
}
public class MpaaRatingAtMostSpecification : Specification<Movie>
{
private readonly MpaaRating_rating;
public MpaaRatingAtMostSpecification(MpaaRating rating)
{
_rating = rating;
}
public override Expression<Func<Movie, bool>> ToExpression()
{
return movie => movie.MpaaRating <= _rating;
}
}
// Controller
public void SomeMethod()
{
var gRating = new MpaaRatingAtMostSpecification(MpaaRating.G);
IReadOnlyList<Movie> movies = repository.Find(gRating); // Getting a list of movies
}
// Repository
public IReadOnlyList<T> Find(Specification<T> specification)
{
return db.Where(specification.ToExpression()).ToList();
}
}
public override Expression<Func<Movie, bool>> ToExpression()شرط خود را نوشته و در سطح کنترلر اگر نیاز به فیلتر Movie ها بر اساس شاخص MpaaRating داشتیم با نمونه سازی از این کلاس به صورت :
{
return movie => movie.MpaaRating <= _rating;
}
var gRating = new MpaaRatingAtMostSpecification(MpaaRating.G);آنرا بر روی Dbset<Movie> اعمال کنیم.پس اگر قرار باشد فیلتری براساس شاخص یا عملگر دیگری اعمال کنید باید یک کلاس جدیدبسازید که از ابستراکت کلاس Specification<T> ارث بری میکند و با پیاده سازی متد ToExpression() شرط مورد نظر خود بنویسید.
IReadOnlyList<Movie> movies = repository.Find(gRating); // Getting a list of movies
و پاس دادن آن به متد Find ریپازیتوری خودمان :
// Repository
public IReadOnlyList<T> Find(Specification<T> specification)
{
return db.Where(specification.ToExpression())
.ToList();
}
لینک مطلب
@fullStackDevs
BY Web Devs
Share with your friend now:
tgoop.com/fullStackDevs/446