عملیات CRUD با Dapper و Repository Pattern درAsp.Net Core 2

چهارشنبه 6 تیر 1397

امروز یاد خواهیم گرفت که چگونه عملیات CRUD را با Asp.Net Core 2.0 Razor Page و با استفاده از Dapper و Repository Pattern انجام دهیم به همین سبب قدم به قدم پیش خواهیم رفت و کد های مربوط به هر گام را در اختیار شما قرار خواهیم داد.

عملیات CRUD با Dapper و Repository Pattern درAsp.Net Core 2

این مقاله نحوه ی انجام عملیات CRUD در Razor Page که در Asp.Net Core 2 با استفاده از Dapper و Repository Pattern معرفی شد را نشان می دهد.

برای تکمیل این موضوع به صورتی ساده گام های زیر را دنبال خواهیم کرد:

گام 1: ساخت Razor Page در Asp.Net Core 2

گام2: ساخت پایگاه داده و جداول

گام3: نصب Dapper

گام4: ساخت کلاس Repository و Interface با موجودیت های مورد نیاز

گام5: ساخت Connection String و دریافت آن در کلاس Repository

گام6:ساخت Razor Page برای عملیات CRUD

گام7:پیاده سازی کد در Razor Page ها برای انجام عملیات CRUD

حال که شش گام را برای تکمیل این مبحث عملی تعریف کردیم اجازه دهید که گام به گام پیش برویم و این پست را کامل کنیم.

گام 1: ساخت Razor Page در Asp.Net Core 2

برای ساخت پروژه ی Asp.Net Core 2 Razor Page ، Visual Studio 2017 نسخه ی 15.3 به بالا را باز کنید و اطمینان حاصل کنید که Net Core SDK 2.0 را روی سیستم خود نصب کرده اید اگر شما این پیکربندی را روی سیستم خود انجام نداده اید لطفا Visual Studio و سیستم های خود را برای این پیکربندی ها به روزرسانی کنید.

امیدوارم آخرین نسخه ی Visual Studio به همراه Net Core SDK 2.0. را نصب کرده باشید. بنابراین Visual Studio را باز کنید و به File Menu > choose New > select Project بروید با این کار یک پنجره ی “New Project” باز خواهد شد. از پنجره ی New Project باید Net Core. را از پنل سمت چپ انتخاب کنید و سپس از پنل وسط “Asp.Net Core Web Application” را انتخاب کنید و یک نام مناسب نظیر “RazorPagesExample” بگذارید و روی OK کلیک کنید.

پس از کلیک روی دکمه ی OK پنجره ی جدیدی باز خواهد شد که می توانید از آن template برای Razor Page را انتخاب کنید.

از اینجا شما باید “Web Application” را برای ساخت اپلیکیشن Razor Page انتخاب کنید و روی OK کلیک کنید. پیکربندی پروژه چند ثانیه و یا چند دقیقه طول خواهد کشید و سرانجام پروژه ی ما برای این ارائه آماده می شود.

گام2: ساخت پایگاه داده و جداول

SSMS [SQL Server Management Studio] را باز کنید و یک پایگاه داده ی جدید به نام “TestDB” بسازید و داخل آن با استفاده از دستور SQL زیر یک جدول به نام “Product” بسازید. حال پایگاه داده ی ما با جداول مربوط به آن آماده است.

--Create Database
CREATE DATABASE TestDB
GO

--Use Created Database
USE TestDB
GO

--Create Table "Product"
CREATE TABLE Product(Id INT PRIMARY KEY IDENTITY(1,1), Name VARCHAR(25), Model VARCHAR(50), Price INT)

--Insert dummy reocrd in table
INSERT INTO Product(Name, Model, Price) VALUES('Nokia 1', 'Nokia', 25000)

SELECT * FROM Product

گام3: نصب Dapper

نصب Dapper یک گام ساده است روی پروژه راست کلیک کنید و “Manage NuGet Packages” را انتخاب کنید یک NuGet Package Manager باز خواهد شد که از آنجا می توانید پکیج هایی که نیاز دارید را جستجو کنید بنابراین ما “Dapper” را جستجو و نصب خواهیم کرد. پس از نصب در قسمت NuGet  که در قسمت “Dependencies” قرار دارد پکیج به صورت زیر در پروژه نشان داده خواهد شد.

گام4: ساخت کلاس Repository و Interface با موجودیت های مورد نیاز

در این مقاله ما عملیات CRUD را برای Product انجام خواهیم داد. چگونگی خواندن داده های محصولات، اضافه کردن یک محصول جدید ، ویرایش محصول موجود و حذف محصول موجود پس از تایید را نشان خواهیم داد. بنابراین اینجا باید یک موجودیت که با Product مرتبط است داشته باشیم.

یک پوشه ی جدید در پروژه به نام “Entity” بسازید و یک کلاس جدید به نام “Product.cs” مانند زیر اضافه کنید این کلاس باید id ، نام، مدل و قیمت محصولات را داشته باشد. اینجا شما می توانید از Data Annotation برای اعتبارسنجی ویژگی ها زمان اضافه کردن یا ویرایش داده های محصولات استفاده کنید.

using System.ComponentModel.DataAnnotations;

namespace RazorPagesExample.Entity
{
    public class Product
    {
        [Key]
        [Display(Name = "Product Id")]
        public int Id { get; set; }

        [Required]
        [Display(Name="Product Name")]
        [StringLength(25, ErrorMessage ="Name should be 1 to 25 char in lenght")]
        public string Name { get; set; }

        [Required]
        [Display(Name = "Model")]
        [StringLength(50, ErrorMessage = "Name should be 1 to 50 char in lenght")]
        public string Model { get; set; }

        [Required]
        [Display(Name = "Price")]        
        public int Price { get; set; }
    }
}

یک پوشه ی دیگر به نام “Repository” در پروژه ی اصلی اضافه کنید و یک interface به عنوان “IProductRepository” که شامل همه ی متد های سمت سرور موردنیاز برای انجام عملیات CRUD می باشد را اضافه کنید.

using RazorPagesExample.Entity;
using System.Collections.Generic;

namespace RazorPagesExample.Repository
{
    public interface IProductRepository
    {
        int Add(Product product);

        List<Product> GetList();

        Product GetProduct(int id);

        int EditProduct(Product product);

        int DeleteProdcut(int id);
    }
}

برای پیاده سازی interface مربوط به “IProductRepository” باید یک کلاس repository  به نام “ProductRepository” مانند زیر بسازیم:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using RazorPagesExample.Entity;
using System.Data.SqlClient;
using Microsoft.Extensions.Configuration;
using Dapper;

namespace RazorPagesExample.Repository
{
    public class ProductRepository : IProductRepository
    {
        IConfiguration _configuration;

        public ProductRepository(IConfiguration configuration)
        {
            _configuration = configuration;
        }

        public int Add(Product product)
        {
            var connectionString = this.GetConnection();
            int count = 0;
            using (var con = new SqlConnection(connectionString))
            {
                try
                {
                    con.Open();
                    var query = "INSERT INTO Product(Name, Model, Price) VALUES(@Name, @Model, @Price); SELECT CAST(SCOPE_IDENTITY() as INT);";
                    count = con.Execute(query, product);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    con.Close();
                }

                return count;
            }
        }

        public int DeleteProdcut(int id)
        {
            var connectionString = this.GetConnection();
            var count = 0;

            using (var con = new SqlConnection(connectionString))
            {
                try
                {
                    con.Open();
                    var query = "DELETE FROM Product WHERE Id =" + id;
                    count = con.Execute(query);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    con.Close();
                }

                return count;
            }
        }

        public int EditProduct(Product product)
        {
            var connectionString = this.GetConnection();
            var count = 0;

            using (var con = new SqlConnection(connectionString))
            {
                try
                {
                    con.Open();
                    var query = "UPDATE Product SET Name = @Name, Model = @Model, Price = @Price WHERE Id = @Id";
                    count = con.Execute(query, product);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    con.Close();
                }

                return count;
            }
        }

        public List<Product> GetList()
        {
            var connectionString = this.GetConnection();
            List<Product> products = new List<Product>();

            using (var con = new SqlConnection(connectionString))
            {
                try
                {
                    con.Open();
                    var query = "SELECT * FROM Product";
                    products = con.Query<Product>(query).ToList();
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    con.Close();
                }

                return products;
            }
        }

        public Product GetProduct(int id)
        {
            var connectionString = this.GetConnection();
            Product product = new Product();

            using (var con = new SqlConnection(connectionString))
            {
                try
                {
                    con.Open();
                    var query = "SELECT * FROM Product WHERE Id =" + id;
                    product = con.Query<Product>(query).FirstOrDefault();
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    con.Close();
                }

                return product;
            }
        }

        public string GetConnection()
        {
            var connection = _configuration.GetSection("ConnectionStrings").GetSection("ProductContext").Value;
            return connection;
        }
    }
}

کلاس “ProductRepository” بالا متد هایی برای انجام عملیات CRUD نظیر “GetProduct”دارد.

Add: برای اضافه کردن یک محصول جدید به پایگاه داده استفاده می شود.

EditProduct: برای ویرایش داده های محصولات موجود استفاده می شود.

DeleteProduct: این متد برای پاک کردن داده های محصولات موجود بعد از تایید استفاده می شود.

GetList: تمام داده های محصولات موجود را می گیرد.

GetProduct: داده های یک محصول مشخص را برمی گرداند.

این متد ها فراخوانی از پایگاه داده را با استفاده از Dapper انجام می دهند.

گام5: ساخت Connection String و دریافت آن در کلاس Repository

حال ما باید connection string پایگاه داده ی خود را تعریف کنیم. همانطور که می دانید Asp.Net Core از appsettings.json برای تعریف اپلیکیشن های مرتبط با پیکربندی استفاده می کند بنابراین ما می خواهیم connection string خود را در فایل appsettings.json مانند زیر تعریف کنیم.

{
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "ConnectionStrings": {
    "ProductContext": "Data Source=AAYUSH-PC; Database=TestDB; UID=sa; Password=*******;"
  }
}

برای گرفتن connection string در Repository ما از قبل کدهایی با repository بالا با استفاده از متد “()GetConnection” که “Connection String” را به صورت کد هایی که در ادامه نشان داده شده است ، می دهد را ساخته ایم.

public string GetConnection()
{
     var connection = _configuration.GetSection("ConnectionStrings").GetSection("ProductContext").Value;
     return connection;
}

گام6:ساخت Razor Page برای عملیات CRUD

حال زمان ساخت Razor Pages برای عملیات CRUD می باشد بنابراین ما سه صفحه در پوشه ی Product ،همانطور که در تصویر زیر نشان داده شده است، می سازیم.

Index.cshtml مسئول نشان دادن لیست تمام محصولات با دکمه های ویرایش و حذف در ستون آخر با داده مرتبط می باشد. جدای از این موضوع یک دکمه ی اضافه در بالای جدول قرار دارد که برای اضافه کردن یک رکورد جدید به عنوان "اضافه کردن محصول جدید" استفاده می شود.

Add.cshtml مسئول اضافه کردن رکوردهای جدید با اعتبار سنجی اینکه آیا همه داده های مورد نیاز وارد شده اند یا نه می باشد.

Edit.cshtml مسئول ویرایش رکوردهای موجود و همچنین اعتبارسنجی برای خواص مورد نیاز می باشد.

حذف داده در صفحه ی Index.cshtml با استفاده از دکمه ی "حذف" مرتبط، مدیریت شده است و رکورد را پس از تایید کاربر و refresh کردن صفحه حذف می کند.

گام7:پیاده سازی کد در Razor Page ها برای انجام عملیات CRUD

پیش از اضافه کردن کدهای عملیات CRUD شما باید کلاس وابستگی های خود را به صورت زیر در متد ConfigurService ثبت کنید.

public void ConfigureServices(IServiceCollection services)
{            
    services.AddMvc();
    services.AddSingleton<IConfiguration>(Configuration);
    services.AddTransient<IProductRepository, ProductRepository>();
}

حال زمان نوشتن کد های عملیات CRUD رسیده است بنابراین کد های زیر را در فایل های مرتبط که عملیات CRUD را مدیریت می کنند اضافه کنید.

فایل Index.cshtml

این فایل شامل کد های نمایش لیست محصولات و دکمه های مربوطه برای حذف یا ویرایش داده ها می باشد و همچنین یک دکمه برای اضافه کردن رکورد جدید نیز دارد.

@page
@model IndexModel
@{
    ViewData["Title"] = "Product page";
}
<script>
    function myFunction(x) {
        $("#item_view").modal();
    };
    $(document).ready(function () {
        $("#success-alert").hide();        
        $("#success-alert").fadeTo(2000, 500).slideUp(500, function () {
            $("#success-alert").slideUp(500);
        });
    });

</script>

<div class="container">
    <div class="mail-box">
        <aside class="lg-side">
            <div class="inbox-head">
                <h3>Razor Page CRUD Operation</h3>
            </div>
            <a class="btn btn-primary btn-sx pull-left" style="margin-top:20px;margin-bottom: 20px;" asp-page="/Product/Add">
                <i class="glyphicon glyphicon-plus"></i> Add New Product
            </a>
            <br />
            @{
                if (!string.IsNullOrEmpty(Model.Message))
                {
                    <div class="alert alert-success" id="success-alert" style="margin-top: 40px;">
                        <button type="button" class="close" data-dismiss="alert">x</button>
                        <strong>@Model.Message ! </strong>
                    </div>
                }
            }

            <div class="inbox-body" style="margin-top:20px;">
                <div class="mail-option">

                    <table class="table table-inbox table-hover" style="border:2px solid black;">
                        <thead>
                            <tr class="unread">
                                <th class="col-sm-2 view-message  dont-show">ID</th>
                                <th class="view-message col-sm-3">NAME</th>
                                <th class="col-sm-2">MODEL</th>
                                <th class="view-message  text-left col-sm-2">PRICE</th>
                                <th class="col-sm-1">OPERATION</th>
                            </tr>
                        </thead>
                        <tbody>
                            @foreach (var item in Model.productList)
                            {
                                <tr>
                                    <td onclick="myFunction(this)" class="view-message  dont-show"><h5>@item.Id</h5></td>
                                    <td onclick="myFunction(this)" class="view-message"><h5>@item.Name</h5></td>
                                    <td onclick="myFunction(this)"><h4 style="margin-top: 5px;"><span class="label label-success ">@item.Model</span></h4></td>
                                    <td onclick="myFunction(this)" class="view-message  text-left"><h5>@item.Price</h5></td>
                                    <td>
                                        <form method="post">
                                            <span class="btn-group pull-right" style="margin-top: 5px">
                                                <a class="btn btn-warning btn-xs" asp-page="/Product/Edit" asp-route-id="@item.Id" style="background-color: green; height: 29px; margin-top: -1px;">
                                                    <i class="glyphicon glyphicon-edit"></i>
                                                </a>

                                                <button type="submit" class="btn btn-danger btn-xs" asp-page-handler="Delete" asp-route-id="@item.Id" style="height: 27px; margin-top: 0px;"
                                                        onclick="return confirm('Are you sure to delete this product?');">
                                                    <i class="glyphicon glyphicon-remove"></i>
                                                </button>

                                            </span>
                                        </form>
                                    </td>
                                </tr>
                            }
                        </tbody>
                    </table>
                </div>
            </div>
        </aside>
    </div>
</div>

فایل Index.cshtml.cs

این فایل به سادگی فقط یک کلاس code-behind برای فایل Index.cshtml که شامل کد برای گرفتن داده ، حذف و انتخاب رکوردها می باشد.

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesExample.Repository;
using System.Collections.Generic;


namespace RazorPagesExample.Pages.Product
{
    public class IndexModel : PageModel
    {
        IProductRepository _productRepository;
        public IndexModel(IProductRepository productRepository)
        {
            _productRepository = productRepository;
        }

        [BindProperty]
        public List<Entity.Product> productList { get; set; }

        [BindProperty]
        public Entity.Product product { get; set; }

        [TempData]
        public string Message { get; set; }
        public void OnGet()
        {
            productList = _productRepository.GetList();
        }

        public IActionResult OnPostDelete(int id)
        {
            if (id > 0)
            {
                var count = _productRepository.DeleteProdcut(id);
                if (count > 0)
                {
                    Message = "Product Deleted Successfully !";
                    return RedirectToPage("/Product/Index");
                }
            }

            return Page();

        }
    }
}

فایل Add.cshtml

این فایل مسئول ساخت UI برای اضافه کردن یک محصول جدید با اعتبار سنجی های لازم که آیا داده وارد شده یا نه می باشد.

@page
@model RazorPagesExample.Pages.Product.AddModel
@{
    ViewData["Title"] = "Add New Product Page";
}

<div>
    <div>
        <div class="modal-content">
            <div class="modal-header">
                <h3 class="modal-title"><strong>New Product</strong></h3>
            </div>
            <div class="modal-body">
                <div class="row">
                    <div class="col-md-4 item_img">
                        <img src="https://www.buehler.ca/images/buttons/Product_Icon.png" class="img-responsive">
                    </div>
                    <div class="col-md-8 item_content">
                        <form method="post">
                            <h4>
                                <span>Please Enter New Product Details!!!</span>
                            </h4>
                            <div class="container">
                                <div class="row">
                                    <div class="col-md-4">
                                        <div class="panel">
                                            <div class="panel-body">
                                                <div class="col-md-12" style="margin-top:15px;">
                                                    <label asp-for="product.Name" style="font-weight:bold;"></label>
                                                    <input type='text' class='form-control' asp-for="product.Name" />
                                                    <span class="alert-danger" asp-validation-for="product.Name"></span>
                                                </div>
                                                <div class="col-md-12" style="margin-top:15px;">
                                                    <label asp-for="product.Model"  style="font-weight:bold;"></label>
                                                    <input type='text' class='form-control' asp-for="product.Model" />
                                                    <span class="alert-danger" asp-validation-for="product.Model"></span>
                                                </div>
                                                <div class="col-md-12" style="margin-top:15px;">
                                                    <label asp-for="product.Price"  style="font-weight:bold;"></label>
                                                    <input type='text' class='form-control' asp-for="product.Price" />
                                                    <span class="alert-danger" asp-validation-for="product.Price"></span>
                                                </div>

                                                <div class="text-center col-md-12" style="margin-top:35px;">
                                                    <button class="btn btn-primary btn-sx" type="submit"><i class="glyphicon glyphicon-plus"></i> Add Product</button>
                                                    <a class="btn btn-primary btn-sx" asp-page="/Product/Index"><i class="glyphicon glyphicon-backward"></i> Product List</a>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

فایل Add.cshtml.cs

این فایل code-behind برای Add.cshtml می باشد و مسئولیت اضافه کردن یک رکورد جدید را دارد و سپس اگر اضافه کردن با موفقیت بود رکورد به صفحه ی اصلی محصولات فرستاده شود.

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesExample.Repository;

namespace RazorPagesExample.Pages.Product
{
    public class AddModel : PageModel
    {
        IProductRepository _productRepository;
        public AddModel(IProductRepository productRepository)
        {
            _productRepository = productRepository;
        }

        [BindProperty]
        public Entity.Product product { get; set; }

        [TempData]
        public string Message { get; set; }
        public IActionResult OnGet()
        {
            return Page();
        }
        public IActionResult OnPost()
        {
            if (ModelState.IsValid)
            {
                var count = _productRepository.Add(product);
                if (count > 0)
                {
                    Message = "New Product Added Successfully !";
                    return RedirectToPage("/Product/Index");
                }                
            }

            return Page();
        }
    }
}

فایل Edit.cshtml

این فایل مسئول ویرایش رکورد های موجود و اعتبارسنجی داده ها می باشد.

@page "{Id:int}"
@model RazorPagesExample.Pages.Product.EditModel
@{
    ViewData["Title"] = "Product Edit Page";
}

<div>
    <div>
        <div class="modal-content">
            <div class="modal-header">
                <h3 class="modal-title"><strong>Edit Product</strong></h3>
            </div>
            <div class="modal-body">
                <div class="row">
                    <div class="col-md-4 item_img">
                        <img src="https://www.buehler.ca/images/buttons/Product_Icon.png" class="img-responsive">
                    </div>
                    <div class="col-md-8 item_content">
                        <form method="post">
                            <h4>
                                <span>Please Update Product Informations !!!</span>
                            </h4>
                            <div class="container">
                                <div class="row">
                                    <div class="col-md-4">
                                        <div class="panel">
                                            <div class="panel-body">
                                                <div class="col-md-12" style="margin-top:15px;">
                                                    <input asp-for="product.Id" type="hidden" />
                                                    <label asp-for="product.Name" style="font-weight:bold;"></label>
                                                    <input type='text' class='form-control' asp-for="product.Name" />
                                                    <span class="alert-danger" asp-validation-for="product.Name"></span>
                                                </div>
                                                <div class="col-md-12" style="margin-top:15px;">
                                                    <label asp-for="product.Model" style="font-weight:bold;"></label>
                                                    <input type='text' class='form-control' asp-for="product.Model" />
                                                    <span class="alert-danger" asp-validation-for="product.Model"></span>
                                                </div>
                                                <div class="col-md-12" style="margin-top:15px;">
                                                    <label asp-for="product.Price" style="font-weight:bold;"></label>
                                                    <input type='text' class='form-control' asp-for="product.Price" />
                                                    <span class="alert-danger" asp-validation-for="product.Price"></span>
                                                </div>

                                                <div class="text-center col-md-12" style="margin-top:35px;">
                                                    <button class="btn btn-primary btn-sx" type="submit">
                                                        <i class="glyphicon glyphicon-edit"></i> Edit Product
                                                    </button>
                                                    <a class="btn btn-primary btn-sx" asp-page="/Product/Index"><i class="glyphicon glyphicon-backward"></i> Product List</a>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

فایل Edit.cshtml.cs

این فایل code-behind برای فایل Edit.cshtml می باشد و شامل کد برای ویرایش رکورد های موجود می باشد و در صورت موفقیت آمیز بودن ویرایش اطلاعات به homepage محصولات بازگردانده می شود.

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesExample.Repository;

namespace RazorPagesExample.Pages.Product
{
    public class EditModel : PageModel
    {
        IProductRepository _productRepository;
        public EditModel(IProductRepository productRepository)
        {
            _productRepository = productRepository;
        }


        [BindProperty]
        public Entity.Product product { get; set; }

        public void OnGet(int id)
        {
            product = _productRepository.GetProduct(id);            
        }

        public IActionResult OnPost()
        {
            var data = product;

            if (ModelState.IsValid)
            {
                var count = _productRepository.EditProduct(data);
                if (count > 0)
                {
                    return RedirectToPage("/Product/Index");
                }
            }

            return Page();
        }
    }
}

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

IProductRepository _productRepository;
public EditModel(IProductRepository productRepository)
{
    _productRepository = productRepository;
}

جدای از این موضوعات برای الحاق اتوماتیک داده با مدل، ما از خصوصیت [BindProperty] با ویژگی های زیر استفاده می کنیم.

[BindProperty]
public Entity.Product product { get; set; }

سرانجام همه چیز تنظیم شده است و حالا می توانیم اپلیکیشن را اجرا کنیم. برای اجرای اپلیکیشن فقط کافی است F5 را فشار دهید تا اپلیکیشن برای شما آماده شود. برای انجام عملیات CRUD برای محصولات باید به URL زیر بروید.

http://localhost:51068/product

برای اضافه کردن محصول جدید روی دکمه ی "اضافه کردن محصول جدید" کلیک کنید سپس یک صفحه ی جدید مانند زیر باز خواهد شد. آیا اگر شما داده های مورد نیاز را پر نکنید و روی " اضافه کردن محصول" کلیک کنید به شما پیغام خطا نشان داده می شود؟

شما می توانید عملیات حذف و ویرایش را با استفاده از دکمه های حذف و ویرایش را در view لیست محصولات انجام دهید.

ایمان مدائنی

نویسنده 1299 مقاله در برنامه نویسان

کاربرانی که از نویسنده این مقاله تشکر کرده اند

در صورتی که در رابطه با این مقاله سوالی دارید، در تاپیک های انجمن مطرح کنید