مروری بر کدهای کلاس SqlHelper
با سلام و تشکر از شما استاد گرامی بابت وقت گرانبهایی که برای آموزش افرادی مانند من هزینه میکنید.در ابتدا عرض کنم ارزش لطف شما را به خوبی میدانم چرا که برنامه نویس بزرگی مثل شما به جای وقت گذاشتن برای کدهای امثال من میتواند به Business خود پرداخته و در همین زمان صرف شده... (اجرکم عندالله)
خواهش دیگری که دارم این است که میتوانید یک سمپل از یکی از کارهایی که از لحاظ فنی مورد تائید شما میباشد را جهت دانلود معرفی کنید تا من و امثال من بتوانیم از آن جهت یادگیری استفاده نماییم؟ (اگر از کارهای خودتان باشد که دیگر ...)
در هر صورت ممنونم از لطف شما.
public class MyController : Controller { [ImportingConstructor] public MyController(MyViewModel viewModel) { ViewModelCore = viewModel; } public MyViewModel ViewModelCore { get; private set; } public void Run() { AddWeakEventListener(ViewModelCore , ViewModelCoreChanged) } private void ViewModelCoreChanged(object sender , PropertyChangedEventArgs e) { if(e.PropertyName=="CurrentItem") { } } }
از آنجا که در دات نت 4.5 یک پیاده سازی خاص از الگوی WeakEvent در کلاس PropertyChangedEventManager موجود در اسمبلی WindowsBase و فضای نام System.ComponentModel انجام شده است در نتیجه توسعه دهندگان این کتابخانه نیز تصمیم به استفاده از این روش گرفتند که نتیجه آن Obsolete شدن کلاس پایه کنترلر در نسخههای 3 به بعد آن است. در روش جدید کافیست به صورت زیر عمل نمایید:
[Export] public class BookController { [ImportingConstructor] public BookController(BookViewModel viewModel) { ViewModelCore = viewModel; } public BookViewModel ViewModelCore { get; private set; } public DelegateCommand RemoveItemCommand { get; private set; } private void ExecuteRemoveItemCommand() { ViewModelCore.Books.Remove(ViewModelCore.CurrentItem); } private bool CanExecuteRemoveItemCommand() { return ViewModelCore.CurrentItem != null; } private void Initialize() { RemoveItemCommand = new DelegateCommand(ExecuteRemoveItemCommand , CanExecuteRemoveItemCommand); ViewModelCore.RemoveItemCommand = RemoveItemCommand; } public void Run() { var result = new List<Book>(); result.Add(new Book { Code = 1, Title = "Book1" }); result.Add(new Book { Code = 2, Title = "Book2" }); result.Add(new Book { Code = 3, Title = "Book3" }); Initialize(); ViewModelCore.Books = new ObservableCollection<Models.Book>(result); PropertyChangedEventManager.AddHandler(ViewModelCore, ViewModelChanged, "CurrentItem"); (ViewModelCore.View as IBookView).Show(); } private void ViewModelChanged(object sender,PropertyChangedEventArgs e) { if(e.PropertyName == "CurrentItem") { RemoveItemCommand.RaiseCanExecuteChanged(); } } }
»ابتدا متدی به نام CanExecuteRemoveItemCommand ایجاد کردیم و کدهای اعتبارسنجی را در آن قرار دادیم؛
»هنگام تعریف Command مربوطه متد بالا را به DelegateCommand رجیستر کردیم:
RemoveItemCommand = new DelegateCommand(ExecuteRemoveItemCommand , CanExecuteRemoveItemCommand);
PropertyChangedEventManager.AddHandler(ViewModelCore, ViewModelChanged, "CurrentItem");
اجرای برنامه:
ابتدا دکمه RemoveItem غیر فعال است:
بعد از انتخاب یکی از گزینه و فراخوانی مجدد متد CanExecuteRemoveItemCommand دکمه مورد نظر فعال میشود:
و در نهایت دکمه RemoveItem فعال خواهد شد:
دانلود سورس پروژه
- چت روم: هر منطقه دارای یک چت روم میباشد که بدون تداخل با همدیگر میتوانند کار خود را انجام دهند.
- وب سایت: بات داری وبسایت میباشد که در بات میتوان با کلیک بر دکمه آن وارد وبسایت شد و درون وب میتوان نظرات خود را برای ادمین فرستاد.
- ذخیره شدن اطلاعات کاربران: تمام چتها، عکسها و حتی مکانهای کاربر در بانک ذخیره میشود.
- قابلیت آپدیت: هنگام آپدیت برنامه، کاربران کاملا مدیریت شده و تداخلی در برنامه ایجاد نخواهد شد و پیغامی به تمام کاربران فرستاده میشود.
- زمان بندی کاربران: امکانی که در هیچ کدام از باتهای دیگر موجود نیست، مدیریت کاربران آنلاین میباشد. GooglemapBot با استفاده از الگوریتمی که برای آن طراحی شده است، میتواند بعد از زمان مشخصی در صورتیکه کاربر فعالیت نداشته باشد، او را از بات خارج کند.
- نمایش افراد آنلاین: یکی دیگر از قابلیتهای بات، امکان نمایش کاربران بر روی نقشه میباشد. هر کاربری بعد از ورود و خروج به صورت آنی با عکس پروفایلش بر روی نقشه نمایش داده میشود.
- محاسبه دقیق فاصله: هنگام ورود به بات، فاصله دقیق کاربر تا تهران محاسبه شده و نمایش داده میشود.
- پنل مدیریت: داخل بات مدیر با وارد کردن پسورد خود شاهد پنل مدیریتی خواهد بود و با خروج پنل بات نمایش داده میشود.
- Filter : یک پراپرتی از نوع string است که درصورت مقداردهی آن، بر روی لیست خروجی ما عملیات فیلترینگ اعمال میشود. مثال :
Filter = "Name==Ali,Age>>10";
- SortBy : یک پراپرتی از نوع string است که درصورت مقداردهی آن، بر روی لیست خروجی ما عملیات چیدمان یا سورتینگ با استفاده از نام فیلد انجام میشود. مثال :
SortBy = "Age";
- IsSortAsc: یک پراپرتی از نوع bool است که مشخص کننده چیدمان به صورت نزولی و یا صعودی است.
- Page : یک پراپرتی از نوع عددی short است. از این پراپرتی برای عملیات Pagination یا صفحه بندی استفاده میشود که مشخص کننده شماره صفحه درخواستی است.
- PageSize : یک پراپرتی از نوع عددی int است که برای مشخص کردن تعداد رکورد در هر صفحه استفاده میشود.
ApplyFiltering | از این متد برای اعمال فیلترینگ روی یک IQueryable استفاده میشود. این متد یک رشته متنی (string) ویا یک GridifyQuery دریافت کرده و پس از اعمال فیلترینگ یک IQueryable بازمیگرداند. |
ApplyOrdering | از این متد برای اعمال چیدمان یا Sorting روی یک IQueryable استفاده میشود. پس از اعمال چیدمان، یک IQueryable را بازمیگرداند. |
ApplyPaging | از این متد برای اعمال صفحه بندی (Pagination) استفاده میشود. پس از اعمال صفحه بندی یک IQueryable را بازمیگرداند. |
ApplyOrderingAndPaging | از این متد برای اعمال همزمان چیدمان و صفحه بندی استفاده میشود که یک IQueryable را باز میگرداند. |
ApplyFilterAndOrdering | از این متد برای اعمال همزمان فیلترینگ و چیدمان استفاده میشود که یک IQueryalbe را باز میگرداند. |
ApplyEverything | از این متد برای اعمال عملیات صفحه بندی، چیدمان و فیلترینگ استفاده میشود که یک IQueryable را باز میگرداند. |
GridifyQueryable | این متد مشابه ApplyEverything است که مقدار یک <QueryablePaging<T را برمیگرداند و دارای یک خصیصه اضافی TotalItems است که در عملیات صفحه بندی عموما نیاز داریم. (تعداد کل رکوردهای موجود در پایگاه داده، با توجه به فیلتر اعمال شده) |
Gridify | متدهای قبلی فقط به query موجود ما یکسری شرط را اضافه میکردند. ولی مسئولیت اجرای query به عهده ما بود. (مثلا با استفاده از ToList.). متد Gridify تمامی شرطها را باتوجه به GridifyQuery دریافتی اعمال کرده، سپس اطلاعات را بارگذاری کرده و یک <Paging<T را بازمیگرداند که کاملا قابل استفاده و بهینه شده برای دیتاگریدها میباشد. |
| |
GetFilteringExpression | این متد expression معادل فیلتر string نوشته شده شما را برمیگرداند که میتوانید از آن به طور مثال در متد Where در Linq استفاده نمایید. |
GetOrderingExpression | این متد expression انتخاب فیلد برای Orderby و OrderByDescending را باتوجه به مقدار وارد شده در فیلد SortBy بازمیگرداند. |
Filtering Operators:
همانطور که در تصویر بالا مشاهده میکنید، برای اعمال فیلترینگهای پیچیده میتوانیم از چهار اپراتور , | ( ) استفاده کنیم. به همین جهت اگر نیاز داشتید که در مقدار جستجوی خود از این علائم استفاده کنید، باید قبل از هرکدام از آنها، علامت \ را اضافه کنید.
مثال رجاکس escape character در JavaScript :
let esc = (v) => v.replace(/([(),|])/g, '\\$1')
مثال #C :
var value = "(test,test2)"; var esc = Regex.Replace(value, "([(),|])", "\\$1" ); // esc = \(test\,test2\)
در بخش بعد با امکانات Mapper توکار Gridify و شخصی سازی آن آشنا خواهیم شد.
تنظیمات CORS در ASP.NET Core
در کروم:
برای رفع این مشکل فقط کافی است دو دستور زیر را با دسترسی مدیریتی اجرا کنید:
dotnet dev-certs https --clean dotnet dev-certs https --trust
این تنظیمات، نیاز به ریاستارت کامل سیستم را هم دارند و تا آن زمان، باز هم خطاهای یاد شده را در مرورگرها مشاهده خواهید کرد.
*یکی از پیش نیازهای این پست مطالعه این دو مطلب (^ ) و (^ ) میباشد.
فرض میکنیم در دیتابیس مورد نظر یک Store به همراه یک جدول به صورت زیر داریم:
[Entity] public interface IBook { [Identifier] string Id { get; } string Title { get; set; } string Isbn { get; set; } }
بعد از انخاب گزینه بالا یک فایل با پسوند tt به پروژه اضافه خواهد شد که وظیفه آن جستجو در اسمبلی مورد نظر و پیدا کردن تمام اینترفیس هایی که دارای EntityAttribute هستند و همچنین ایجاد کلاسهای متناظر جهت پیاده سازی اینترفیسهای بالا است. در نتیجه ساختار پروژه تا این جا به صورت زیر خواهد شد.
واضح است که فایلی به نام Book به عنوان پیاده سازی مدل IBook به عنوان زیر مجموعه فایل DatabaseContext.tt به پروژه اضافه شده است.
تا اینجا برای استفاده از Context مورد نظر باید به صورت زیر عمل نمود:
DatabaseContext context = new DatabaseContext(); context.Books.Add(new Book());
public interface IUnitOfWork { BrightstarEntitySet<T> Set<T>() where TEntity : class; void DeleteObject(object obj); void SaveChanges(); }
نکته: برای حذف یک آبجکت از Store، باید از متد DeleteObject تعبیه شده در Context استفاده نماییم. در نتیجه متد مورد نظر نیز در اینترفیس بالا در نظر گرفته شده است.
استفاده از IOC Container جهت رجیستر کردن IUnitOfWrok
در این قدم باید IUnitOfWork را در یک IOC container رجیستر کرده تا در جای مناسب عملیات وهله سازی از آن میسر باشد. من در اینجا از Castle Windsor Container استفاده کردم. کلاس زیر این کار را برای ما انجام خواهد داد:
public class DependencyResolver { public static void Resolve(IWindsorContainer container) { var context = new DatabaseContext("type=embedded;storesdirectory=c:\brightstar;storename=test "); container.Register(Component.For<IUnitOfWork>().Instance(context).LifestyleTransient()); } }
public class BookService { public BookService(IUnitOfWork unitOfWork) { UnitOfWork = unitOfWork; } public IUnitOfWork UnitOfWork { get; private set; } public IList<IBook> GetAll() { return UnitOfWork.Set<IBook>().ToList(); } public void Add() { UnitOfWork.Set<IBook>().Add(new Book()); } public void Remove(IBook entity) { UnitOfWork.DeleteObject(entity); } }
نکته: در حال حاضر امکان جداسازی مدلهای برنامه (تعاریف اینترفیس) در قالب یک پروژه دیگر(نظیر مدل CodeFirst در EF) در B*Db امکان پذیر نیست.
نکته : برای اضافه کردن آیتم جدید به Store نیاز به وهله سازی از اینترفیس IBook داریم. کلاس Book ساخته شده توسط DatabaseContext.tt در عملیات Insert و update کاربرد خواهد داشت.