اتصال موجودیت در EF Core و جستجو در EF Core – جلسه ۵۳

Join Entities & Serach in EF Core - Session 53-min

در این جلسه به بررسی نحوه اتصال موجودیت در EF Core و وب اپلیکشن ASP.NET Core خواهیم پرداخت. همچنین، روش جستجو در EF Core و ایجاد Query مناسب با استفاده از Lambda Expression (LINQ) را شرح خواهیم داد. در جلسات گذشته موجودیت‌های مختلفی برای وب اپلیکشن خود ایجاد نمودیم که برخی از آنها با هم در ارتباط بودند. در این جلسه به اتصال این موجودیت‌ها جهت نمایش در نما و گزارشات خواهیم پرداخت. سپس روش جستجو در لیست را با استفاده از EF Core و LINQ را با جزئیات کامل بررسی میکنیم.

اتصال موجودیت در EF Core

جهت اتصال موجودیت در EF Core میبایست از متد Join استفاده نماییم. با استفاده ازاین متد، میتوانیم یک موجودیت (جدول) را به یک یا چندین موجودیت (جدول) دیگر متصل نماییم. همانگونه که در تصویر زیر مشاهده میکنید، در لیست نمایش داده شده رکورد‌‎های Cost، به جای نمایش نام Category مقدار ID آن نمایش داده شده است.

اتصال موجودیت‌ها در EF Core
در واقع این لیست نشان دهنده‌ی مقادیر موجود در موجودیت Cost است که درون آن با توجه به نرمال سازی موجودیت‌ها، مقدار CategoryID ذخیره میگردد. پس برای نمایش CategoryName در لیست فوق، میبایست موجودیت Cost و Category را به هم متصل نماییم و فیلد های مورد نیاز را به صورت یک لیست به این نما ارسال کنیم.

برای پیاده‌سازی اتصال بین این دو موجودیت و نمایش آن در نما متناظر، ابتدا نیاز به یک ViewModel جدید خواهیم داشت که دارای فیلدهای متناسب با نمای مورد نظر باشد.

    public class CostList
    {
        public int ID { get; set; }
        public decimal Amount { get; set; }
        public string Comment { get; set; }
        public string CategoryName { get; set; }
        public PaymentMethods? PaymentMethod { set; get; }
    }

سپس درون ICostRepository یک متد جدید ایجاد نموده که خروجی آن از نوع لیستی از ViewModel فوق میباشد.

    public interface ICostRepository
    {
        Cost GetCostByID(int id);
        IEnumerable<Cost> GetAllCost();
        Cost Create(Cost NewCost);
        Cost Update(Cost UpdateCost);
        Cost Delete(int id);
        List<CostList> GetCostList(string searchby, string searchfor);
    }

سپس اقدام به پیاده‌سازی متد در ریپازیتوری یا ریپازیتوری‌ها میکنیم.

        public List<CostList> GetCostList()
        {
            var CL = context.Costs.Join(context.Categories, costen => costen.CategoryID, caten => caten.ID, (costen, caten) => new { costen, caten }).
                Select(sel => new 
                {
                    sel.costen.ID,
                    sel.costen.Amount,
                    sel.costen.Comment,
                    sel.costen.PaymentMethod,
                    sel.caten.CategoryName
                }).ToList();
            List<CostList> costList = new();
            foreach (var cost in CL)
            {
                costList.Add(new CostList
                {
                    ID = cost.ID,
                    Amount = cost.Amount,
                    Comment = cost.Comment,
                    PaymentMethod = cost.PaymentMethod,
                    CategoryName = cost.CategoryName
                });
            }
            return costList;
        }

همانگونه که در قطعه کد فوق مشاهده میکنید، عملیات اتصال در قسمت ریپازیتوری انجام گردید و با استفاده از متد Join اتصال بین دو موجودیت برقرار گردید. سپس میتوانیم از این متد جدید در قسمت‌ها‌ی مورد نیاز استفاده نماییم.

        [HttpGet]
        public IActionResult Index()
        {
            var costs = costRepository.GetCostList();
            return View(costs);
        }

همچنین تغییرات زیر را در نمای Cost/Index اعمال میکنیم.

@model IEnumerable<CostList>

@{
    ViewBag.Title = "Cost List";
}
<div class="row">
    <div class=col-3>
        <a asp-controller="cost" asp-action="create" class="btn btn-primary mx-2 my-2">Create New Cost</a>
    </div>
</div>
<table class="table table-dark">
    <thead>
        <tr>
            <th>ID</th>
            <th>Amount</th>
            <th>Category</th>
            <th>Comment</th>
            <th>Payment Method</th>
            <th colspan="3" class="text-center">Actions</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var cost in Model)
        {
            <tr>
                <td>@cost.ID</td>
                <td>@cost.Amount</td>
                <td>@cost.CategoryName</td>
                <td>@cost.Comment</td>
                <td>@cost.PaymentMethod</td>
                <form asp-controller="cost" asp-action="delete" asp-route-id="@cost.ID" method="post">
                <td><a class="btn btn-primary d-block" asp-controller="cost" asp-action="detail" asp-route-id="@cost.ID">View</a></td>
                <td><a class="btn btn-info btn-block d-block" asp-controller="cost" asp-action="update" asp-route-id="@cost.ID">Edit</a></td>
                <td><button class="btn btn-danger btn-block d-block" type="submit">Delete</button></td>
                </form>
            </tr>
        }
    </tbody>
</table>

در نتیجه لیست فوق به شکل زیر تغییر کرده و نام دسته‌بندی به جای کد آن نمایش داده میشود.

نمایش نما پس از اتصال موجودیت‌ها

جستجو در EF Core

جهت جستجو در پایگاه داده و نمایش لیستی که مطابق با شرایط جستجو باشد، میتوانیم از متد Where استفاده نماییم. در این متد و با استفاده از Lambda Expression میتوانیم از عملگرهای مقایسه‌ایی مانند بزرگتر، کوچکتر، برابر یا نا برابر و یا همچنین متد‌های Contains، Equal، StartsWith و EndsWith نیز استفاده نمود. ما در این جلسه از عملگر برابر با و Contains استفاده خواهیم نمود. شما به عنوان تمرین میتوانید از دیگر عملگرها استفاده نمایید. ضمنا متد Contains برای زمانی استفاده میگردد که ما به دنبال رشته‎‌هایی میگردیم که حاوی عبارت مورد نظر ما باشد.

برای اعمال این تغییرات، ابتدا در نمای خود فرم مربوط به جستجو را اضافه میکنیم.

        <form asp-controller="Cost" asp-action="Index" method="get" class="my-2 mx-2">
            <div class="input-group">
                <select class="form-select" id="inputSearch" name="searchby">
                    <option selected value="">Search by...</option>
                    <option value="comment">Comment</option>
                    <option value="category">Category</option>
                </select>
                <input name="searchfor" class="form-control" id="inputSearch" aria-describedby="inputSearchComment" aria-label="Search">
                <button class="btn btn-outline-secondary" type="submit" id="inputSearch">Search</button>
                <a class="btn btn-outline-primary" type="button" asp-controller="cost" asp-action="index">Clear Search</a>
            </div>
        </form>

همانگونه که در قطعه کد فوق مشاهده میکنید، ما یک فرم به نمای Cost/Index اضافه نمودیم. متد این فرم Get میباشد و عبارات مربوط به جستجو را بوسیله Query String به کنترلر ارسال میکند. پس ما باید در کنترلر و اکشن متد مربوطه، تغییراتی اعمال نماییم تا عبارات جستجو را بتوانیم به کنترلر و سپس ریپازیتوری ارسال نماییم.

        [HttpGet]
        public IActionResult Index(string searchby, string searchfor)
        {
            //var costs = costRepository.GetAllCost();
            var costs = costRepository.GetCostList(searchby, searchfor);
            return View(costs);
        }

حال میبایست تغییرات مورد نظر را برای اینترفیس و ریپازیتوری اعمال نماییم.

    public interface ICostRepository
    {
        Cost GetCostByID(int id);
        IEnumerable<Cost> GetAllCost();
        Cost Create(Cost NewCost);
        Cost Update(Cost UpdateCost);
        Cost Delete(int id);
        List<CostList> GetCostList(string searchby, string searchfor);
    }

سپس با توجه به تغییرات اینترفیس، ریپازیتوری متناظر خود را بروزرسانی میکنیم.

        public List<CostList> GetCostList(string searchby, string searchfor)
        {
            var CL = context.Costs.Join(context.Categories, costen => costen.CategoryID, caten => caten.ID, (costen, caten) => new { costen, caten }).
                Select(sel => new 
                {
                    sel.costen.ID,
                    sel.costen.Amount,
                    sel.costen.Comment,
                    sel.costen.PaymentMethod,
                    sel.caten.CategoryName
                }).ToList();
            if(searchby == "comment" && searchfor != null)
            {
                CL = CL.Where(ser => ser.Comment.ToLower().Contains(searchfor.ToLower())).ToList();
            }
            if (searchby == "category" && searchfor != null)
            {
                CL = CL.Where(ser => ser.CategoryName.ToLower() == searchfor.ToLower()).ToList();
            }
            List<CostList> costList = new();
            foreach (var cost in CL)
            {
                costList.Add(new CostList
                {
                    ID = cost.ID,
                    Amount = cost.Amount,
                    Comment = cost.Comment,
                    PaymentMethod = cost.PaymentMethod,
                    CategoryName = cost.CategoryName
                });
            }
            return costList;
        }

در صورت نیاز به جزئیات بیشتر، میتوانید ویدئو آموزشی این جلسه را تماشا نمایید. همچنین برای آگاهی از جلسات بعدی این دوره آموزشی، ما را در اینستاگرام، تلگرام، یوتیوب و آپارات دنبال کنید. ضمنا لیست کامل جلسات در این قسمت در دسترس شما میباشد و سورس کد این جلسه را میتوانید از GitHub ما دانلود نمایید.

تماشای ویدیو در یوتیوب ما

دانلود اسلایدهای آموزشی این جلسه از اینجا

برچسب ها

1 1 رای
امتیازدهی به مقاله
اشتراک در
اطلاع از
guest
0 نظرات
بازخورد (Feedback) های اینلاین
مشاهده همه دیدگاه ها
0
افکار شما را دوست داریم، لطفا نظر دهید.x