public class ProductService { public IEnumerable<Product> GetOrderedProducts() { using (var ctx = new Entites()) { return ctx.Products.OrderBy(x => x.Name).ToList(); } } }
public interface IUnitOfWork { IDbSet<TEntity> Set<TEntity>() where TEntity : class; int SaveAllChanges(); } public class Entites : DbContext, IUnitOfWork { public virtual DbSet<Product> Products { get; set; } // This is virtual because Moq needs to override the behaviour public new virtual IDbSet<TEntity> Set<TEntity>() where TEntity : class // This is virtual because Moq needs to override the behaviour { return base.Set<TEntity>(); } public int SaveAllChanges() { return base.SaveChanges(); } }
public class ProductService { private readonly IDbSet<Product> _products; private readonly IUnitOfWork _uow; public ProductService(IUnitOfWork uow) { _uow = uow; _products = _uow.Set<Product>(); } public IEnumerable<Product> GetOrderedProducts() { return _products.OrderBy(x => x.Name).ToList(); } }
[TestFixture] public class ProductServiceTest { private readonly ProductService _productService; public ProductServiceTest() { IQueryable<Product> data = GetRoadNetworks().AsQueryable(); var mockSet = new Mock<DbSet<Product>>(); mockSet.As<IQueryable<Product>>().Setup(m => m.Provider).Returns(data.Provider); mockSet.As<IQueryable<Product>>().Setup(m => m.Expression).Returns(data.Expression); mockSet.As<IQueryable<Product>>().Setup(m => m.ElementType).Returns(data.ElementType); mockSet.As<IQueryable<Product>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator()); var context = new Mock<Entites>(); context.Setup(c => c.Products).Returns(mockSet.Object); context.Setup(m => m.Set<Product>()).Returns(mockSet.Object); _productService = new ProductService(context.Object); } private IEnumerable<Product> GetRoadNetworks() { return new List<Product> { new Product { Id = 1, Name = "A" }, new Product { Id = 2, Name = "B" }, new Product { Id = 3, Name = "C" } }; } [Test] public void GetOrderedProductTest() { IEnumerable<Product> products = _productService.GetOrderedProducts(); List<string> names = products.Select(x => x.Name).ToList(); var expected = new List<string> {"A", "B", "C"}; CollectionAssert.AreEqual(names, expected); } }
در اینجا غیر از مورد زمانبندی انجام پروژه سعی شده است به دیگر موارد غیره از قبیل شناخت نیازمندیها، نحوه بستن قرارداد، نحوه قیمت دهی و ... اشاره نشود.
در ابتدا در مورد موضوعات کلی و عمومی بحث میکنیم.
1- انتخاب فریمورک، فریمورکهای فراوان و مختلفی برای کار با زمینههای مختلف نرم افزاری در جهان وجود دارند که هرکدام مزایا و معایبی دارند. این روزها استفاده از فریمورکها به قدری جای افتاده است و به اندازهای امکانات دارند که حتی ممکن است امکانات یک فریم ورک باعث شود از یک زبانی که در تخصصتان نیست استفاده کنید و آنرا یاد بگیرید.
2- زمانبندی انجام پروژه، به نظر خود بنده، سختترین و اساسیترین مرحله، برای هر پروژهای، زمانبندی مناسب آن است که نیازمندی اساسی آن، شناخت سایر مواردی است که در این متن بدانها اشاره میشود. زمانبندی دقیق، قرار ملاقاتها و تحویل بهموقع پیش نمایشهای نرم افزار، ارتباط مستمر با کارفرما و تحویل حتی زودتر از موعد پروژه باعث رضایت بیشتر کارفرما و حس اطمینان بیشتر خواهد شد. اگر در تحویل پروژه دیرکرد وجود داشته باشد، باعث دلسردی کارفرما و نوعی تبلیغ منفی خواهد بود. حتی زمانبندی و تحویل به موقع پروژه برای کارفرما بیشتر از کیفیت اهمیت دارد.
3- انتخاب معماری نرم افزار، معماری نرم افزار در اصل تعیین کننده نحوه قطعه بندی و توزیع تکههای نرم افزار، نحوه ارتباط اجزاء،، قابلیت تست پذیری، قابلیت نگهداری و قابلیت استفاده مجدد از کدهای تولید شده میباشد. یکی از اهداف اساسیای که باید در معماری نرمافزار بدان توجه کرد، قابلیت استفاده مجدد از کد است. در یک معماری خوب ما قطعاتی درست خواهیم کرد که بهراحتی میتوانیم از آن در نرمافزارهای دیگر نیز استفاده کنیم. البته قابلیت تست پذیری و قابلیت نگهداری نیز حداقل به همان اندازه اهمیت دارند. در این سایت موارد بسیار زیاد و کاملی جهت ساخت معماری مناسب و design patterns وجود دارد که میتوانید در اینجا یا اینجا مشاهده کنید.
4- قابلیت اجرا بر روی پلتفرمهای مختلف، هرچند این مورد ممکن است بیشتر به نظر کارفرما بستگی داشته باشد، اما در کل اگر کارفرما بتواند سیستم را در پلتفرمهای مختلفی اجرا کند، راضیتر خواهد شد. اگر قصد فروش نرمافزار طراحی شده را داشته باشیم، در اینصورت نیز میتوانیم کاربران پلتفرمهای مختلف را مورد هدف قرار دهیم یا سیستم را در سرورهای مختلفی میزبانی کنیم.
5- انتخاب سیستم بانک اطلاعاتی و نحوه ارتباط با آن. باید تصمیم بگیرید که از چند سیستم بانک اطلاعاتی، چگونه و به چه منظوری استفاده خواهید کرد. مواردی وجود دارند که سیستم را طوری طراحی کردهاند تا در زمان بهره برداری امکان انتخاب بانکهای اطلاعاتی یا نحوه ذخیره اطلاعات برای مدیر سیستم وجود دارد. مثلا در BlogEngine.net میتوان انتخاب کرد که اطلاعات در SQL Server ذخیره شوند یا در سیستم فایل مبتنی بر XML . بحثهای بسیار زیادی در این سایت و کل فضای وب پیرامون نحوه انتخاب و استفاده از ORM ها، چگونگی معماری مناسب آن وجود دارد. بطور مثال همیشه بحث سر اینکه از الگوی Repository استفاده شود یا نشود وجود دارد! باید به خودمان پاسخ دهیم که آیا واقعاً نیاز است که سیستم را برای امکان استفاده از Ormهای مختلف طراحی کنیم؟
6- نحوه ماژول بندی سیستم و امکان افزودن راحت ماژولهای جدید به آن. امروزه و با افزایش کاربران محصولات انفورماتیک که باعث بیشتر شدن سواد مصرف کننده در این زمینه و بالطبع افزایش نیازهای وی شده، همیشه احتمال اینکه کارفرما موارد جدیدی را بخواهد وجود خواهد داشت. باید سیستم را طوری طراحی کرد که حتی بتوان بدون توقف اجرای آن موارد جدید (پلاگینهای جدید) را بدان افزود و اجرا کرد.
7- میزان مشارکت دیگران در رفع نیازمندیهای کابران. ممکن است این گزینه در درجه اول زیاد با اهمیت جلوه ندهد، اما با تعمق در وبسایتها و نرمافزارهای بزرگ که هم اکنون در دنیا صاحب نامی شدهاند میبینیم همه آنها تمهیداتی اندیشیدهاند تا با وجود کپسوله کردن موارد پس زمینه، امکاناتی را در جهت مشارکت دیگران فراهم کنند. اکثر شبکههای اجتماعی api هایی را مهیا کرده اند که افراد ثالث میتوانند از آنها استفاده کنند. اکثر سیستمهای مدیریت محتوا و ابزارهای e-commerce تمهیداتی را برای راحتی ساخت plugin و apiهای برای راحتی برقراری ارتباط اشخاص ثالث اندیشیدهاند. از نظر این جانب موارد 6 و 7 برای ادامه حیات و قابلیت رقابت پذیری پروژه از درجه اهمیت زیادی برخوردار است.
8- معماری Multi tenancy بلی یا خیر؟ Multi tenancy یک از بحثهای مهم رایانش ابری است. در این حالت فقط یک نمونه از نرم افزار در سمت سرور در حال اجراست ولی کاربر یا گروهی از کاربران دید یا تنظیمات متفاوتی از آنرا دارند.
در ادامه به موارد فنیتری خواهیم پرداخت:
9- بحث انتخاب ابزار Dependency injection مناسب و مهیا سازی امکاناتی جهت هرچه راحتتر کردن امکان تنظیم و register کردن اشیا بدان. نحوه پیکربندی مناسب این مورد میتواند کد نویسی را برایتان بسیار راحت کند. دات نت تیپس مطالب بسیاری را در این مورد ارائه داده است میتوانید اینجا را ببینید.
10- کشینگ. استفاده از یک سیستم کشینگ مناسب در ارتباط با بانکهای اطلاعاتی و یا سایر سیستمهای ذخیره و بازیابی اطلاعات میتواند کمک بسیاری در پرفرمنس برنامه داشته باشد. سیستمها و روشهای مختلفی در مورد کشینگ وجود دارند. میتوانید برای اطلاعات بیشتر اینجا را مطالعه فرمایید.
11- Logging. یک سیستم لاگر مناسب میتواند وارنینگها و خطاهای بوجود آمده در سیستم را در یک رسانه ذخیره سازی حفظ کند و شما به عنوان توسعه دهنده میتوانید با مطالعه آن نسبت به رفع خطاهای احتمالی و بهبود در نسخههای آتی کمک بگیرید.
12- Audit logging یا Activity logging و Entity History. میتوانید کل یا برخی از فعالیتهای کاربر را در یک رسانه ذخیره سازی، ذخیره کنید، از قبیل زمان ورود و خروج، آیپی مورد استفاده، سیستم عامل، مرورگر، بازبینی از صفحه وغیره. همچنین در audit logging میتوانید زمانهای دقیق تغییرات مختلف موجود در موجودیتهای سیستم، فرد انجام دهنده تغییرات، سرویس انجام دهنده تغییرات، مدت زمان سپری شده و ... را ذخیره کرد. Entity History : ممکن است تصمیم بگیرید که کل اتفاقاتی را که برای یک موجودیت در طول زمان حیاتش در سیستم میافتد، ذخیره کنید.
13- Eventing ، Background Workerها و Backgroudn jobs ( Scheduled tasks ). باید سیستم را طوری طراحی کرد که بتواند به تغییرات و اتفاقات افتاده در سیستم پاسخ دهد. همچنین این مورد یکی از نیازمندیهای معماری بر اساس پلاگین است. Background Workerها در واقع کارهایی هستند که در پس زمینه انجام میشوند و نیازی نیست که کاربر برای اتمام آن منتظر بماند؛ مثلاً ارسال ایمیل خوش آمدگویی را میتوان با آن انجام داد. Background jobs کمی متفاوت هستند در واقع اینها فعالیتهای پس زمینهای هستند که ممکن است در فواصل زمانی مختلف اتفاق بیافتند، مثل پاکسازی کش در فواصل زمانی مناسب. در سیستمهای مختلف تمهیداتی برای ذخیره سازی فعالیتهایی که توسط background jobs انجام میشود اندیشیده میشود.
14- پیکربندی صحیح نحوه ذخیره و بازیابی تنظیمات سیستم. در یک سیستم ممکن است شما تنظیمات متعددی را در اختیار کاربر و یا حتی خودتان قرار دهید. باید سیستم را طوری طراحی کنید که بتواند با راحتترین و سریعترین روش ممکن به تنظیمات موجود دستیابی داشته باشد.
15- خطاهای کاربر را در نظر بگیریم، باید یادمان باشد کاربر ممکن الخطاست و ما برای رضایت مشتری و قابلیت اتکای هرچه بیشتر برنامه باید سیستم را طوری طراحی کنیم که امکان برگشت از خطا برای کاربر وجود داشته باشد. مثلاً در SoftDelete مواردی که حذف میشوند در واقع به طور کامل از بانک اطلاعاتی حذف نمیشوند بلکه تیک حذف شده میخورند. پس امکان بازگردانی وجود خواهد داشت.
16- Mapping یا Object to object mapping. در توسعه شیءگرا مخصوصاً در معماریهایی مثل MVC یا Domain driven در موارد بسیاری نیاز خواهید داشت که مقادیر اشیاء مختلفی را در اشیای دیگری کپی کنید. سیستمهای زیادی برای این کار موجود هستند. باید تلاش کرد ضمن اینکه یک سیستم مناسب انتخاب کنیم، باید تمهیدی بیاندیشیم که تنظیمات آن شامل کد نویسی هرچه کمتری باشد.
17- Authorization یا تعیین هویت. باید با مطالعه و بررسی، سیستم و ابزار مناسبی را برای هویت سنجی اعضاء، تنظیم نقشها و دسترسیهای کاربران انتخاب کرد. باید امکان عضویت از طریق شبکههای اجتماعی مختلف را مورد بررسی قرار داد.
18- سرویسهای Realtime. کاربری یکی از مطالب شما را میپسندد و شما نوتیفیکشن آنرا سریع در صفحهای که باز کردید میبینید. این یک مورد بسیار کوچکی از استفاده از سرویسهای realtime هست. ابزارهای مختلفی برای زبانها و فریمورکهای مختلف وجود دارند؛ مثلاً میتوانید اینجا را مطالعه کنید.
19- هندل کردن خطاهای زمان اجرا، در سیستمهای قدیمی یکی از کابوسهای کاربران، قطعی سیستم، هنگ کردن با کوچکترین خطا و موارد این چنینی بود. با تنظیم یک سیستم Exception handling مناسب هم میتوانیم گزارشاتی از خطاهای بوجود آمده را تهیه کنیم، هم میتوانیم کاربر را در جهت انجام صحیح کارها هدایت کنیم و هم از کرش بیجای نرمافزار جلوگیری کنیم.
20- استفاده از منابع ابری یا توزیع شده، امروزه برای بسیاری از کارها تمهیداتی از طرف شرکتهای بزرگ به صورت رایگان و یا غیر رایگان اندیشیده شده است که به راحتی میتوان از آنها استفاده کرد. برای نمونه میتوان از سرویسهای Email به عنوان سادهترین و معمولترین این سیستمها یاد کرد. اما امروزه شرکتها حتی امکاناتی جهت ذخیره سازی دادههای blob (مجموعه ای از بایتها با حجم زیاد) را ارائه میدهند؛ امکانات دیگری نظیر کم کردن حجم تصاویر، تبدیل انواع mime typeها و ...
21- امنیت، فریمورکها اغلب موارد امنیتی پایهای را به صورت مطلوب یا نسبتا مطلوبی رعایت میکنند؛ ولی با اینحال باید در مورد امنیت سیستمی که توسعه میدهیم مطالعه داشته باشیم و موارد امنیتی ضروری را رعایت کنیم و همیشه مواظب باشیم که آنها را رعایت کنیم.
EF Code First #12
- همچنین در مطلب «آناتومی یک گزارش خطای خوب» با کلیات مفیدی در مورد با جزئیات فنی بحث کردن، آشنا خواهید شد.
استفاده از ادیتور CKEditor در صفحات ASP.NET
مطالب مفیدی داری که مشتاقانه اونها رو پیگیری میکنم
راجع به این ادیتور یه سوال داشتم
ایا استفاده از سورس بدون لایسنس امکانپذیره؟
یا حتما لایسنس میخواد؟
من از کجا میتونم سورسش رو داشته باشم؟
بسیار بسیار متشکرم
گودرزی
1- EF Code First #8
2- مباحث تکمیلی مدلهای خود ارجاع دهنده در EF Code First
3- نگاهی به اجزای تعاملی Twitter Bootstrap
هدف از مطلب جاری نحوه نمایش منویهای چند سطحی میباشد، ابتدا مثال کامل زیر را در نظر بگیرید :
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Menu.Models.Entities { public class Category { public int Id { get; set; } public string Name { get; set; } public int? ParentId { get; set; } public virtual Category Parent { get; set; } public virtual ICollection<Category> Children { get; set; } } } public class MyContext : DbContext { public DbSet<Category> Category { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { // Self Referencing Entity modelBuilder.Entity<Category>() .HasOptional(x => x.Parent) .WithMany(x => x.Children) .HasForeignKey(x => x.ParentId) .WillCascadeOnDelete(false); base.OnModelCreating(modelBuilder); } }
هدف از این بحث، نحوه نمایش گروه محصولات داخل منو به صورت چند سطحی میباشد، جهت نمایش میبایست از تکنیک recursive function استفاده کنید، ابتدا در نظر داشته باشید که ساختار منوی تشکیل شده میبایست بدین صورت باشد :
این حالت میتواند تا n سطح پیش برود، حال نحوه نمایش در View مربوطه باید به صورت زیر باشد :
@using Menu.Helper @model IEnumerable<.Models.Entities.Category> @ShowTree(Model) @helper ShowTree(IEnumerable<Menu.Models.Entities.Category> categories) { foreach (var item in categories) { <li class="@(item.Children.Any() ? "dropdown-submenu" : "")"> @Html.ActionLink(item.Name, actionName: "Category", controllerName: "Product", routeValues: new { Id = item.Id, productName = item.Name.ToSeoUrl() }, htmlAttributes: null) @if (item.Children.Any()) { <ul> @ShowTree(item.Children) </ul> } </li> } }
یک نکته :
در خط 9 این مورد را که آیا آیتم جاری فرزندی دارد چک کرده ایم اگر داشته باشد کلاس dropdown-submenu را به li جاری اضافه میکند.
در قسمتهای قبلی (^ و ^) راهکارهایی جهت بالا بردن کارآیی، ارائه شد. در ادامه، به آخرین قسمت این سری اشاره خواهم کرد.
فراخوانی متد شناسایی تغییرات
یادآوری: قبل از هر چیز با توجه به این مقاله دانستن این نکته الزامی است که فراخوانی برخی متدها مانند DbSet.Add سبب فراخوانی DataContext.ChangeTracker.DetectChanges خواهند شد.
فرض کنید قصد افزودن 2000 موجودیت دانش آموز را دارید:
for (int i = 0; i < 2000; i++) { Pupil pupil = GetNewPupil(); db.Pupils.Add(pupil); } db.SaveChanges();
اگر به تصویر بالا دقت کنید بیش از 34 ثانیه (خط 193 قسمت سوم شکل) جهت افزودن 2000 موجودیت به کانتکست سپری شده است. در حالی که درج این 2000 موجودیت کمی بیش از 1 ثانیه (خط 195 قسمت سوم شکل) که 379 میلی ثانیه (قسمت دوم شکل) آن مربوط به اجرای کوئری اختصاص یافته طول کشیده است.
بیشترین زمان صرف شدهی برای درج 2000 موجودیت، در کد برنامه سپری شده است که با بررسی بیشتر در پروفایلر، متوجه زمان بر بودن فراخوانی متد ()DetectChanges که در فضای نام Data.Entity.Core وجود دارد خواهید شد. این متد 2000 بار به تعداد موجودیت هایی که قصد داریم به بانک اطلاعاتی اضافه نماییم، فراخوانی شده است.
همانطور که در شکل بالا مشخص است همان 34 ثانیه جهت ردیابی تغییرات صرف شده است. EF ردیابی تغییرات را بصورت پیش فرض هر زمانی که قصد افزودن یا ویرایش موجودیتی را داشته باشید، انجام خواهد داد و هر چه موجودیتهای بیشتری را بخواهید ویرایش یا اضافه نمایید، این زمان نیز بیشتر خواهد شد. در حقیقت زمان لازم برای الگوریتم ردیابی تغییرات بصورت نمایی با رشد موجودیتها افزوده میشود. به عبارت دیگر اگر این تعداد موجودیتها را به 4000 عدد برسانید، مدت زمان لازم بیش از 2 برابر افزوده خواهد شد.
راه حل اول:
استفاده از متد ()AddRange ارائه شده در EF6 که جهت درج دستهای (Bulk Insert) ارائه شده است:
var list = new List<Pupil>(); for (int i = 0; i < 2000; i++) { Pupil pupil = GetNewPupil(); list.Add(pupil); } db.Pupils.AddRange(list); db.SaveChanges();
راه حل دوم:
در سناریوهای پیچیده، مانند درج دستهای چندین موجودیت، شاید مجبور به خاموش نمودن این قابلیت شوید:
db.Configuration.AutoDetectChangesEnabled = false;
ردیابی تغییرات
هنگامی که موجودیتی را از بانک اطلاعاتی دریافت نمایید، میتوانید آن را ویرایش نمایید و مجددا به بانک اطلاعاتی اعمال نمایید. چون EF اطلاعی از قصد شما برای موجودیت نمیداند، مجبور است تغییرات شما را زیر نظر بگیرد که این زیر نظر گرفتن، هزینه و سربار دارد و این سربار و هزینه برای دادههای زیاد، بیشتر خواهد شد. بنابراین اگر قصد دارید اطلاعاتی فقط خواندنی را از بانک اطلاعاتی دریافت نمایید، بهتر است صراحتا به EF بگویید این موجودیت را تحت ردیابی قرار ندهد.string city = "New York"; List<School> schools = db.Schools .AsNoTracking() .Where(s => s.City == city) .Take(100) .ToList();
استفاده از متد AsNoTracking در کد بالا سبب خواهد شد 100 مدرسه که در شهر نیویورک وجود دارد توسط EF، بدون تحت نظر گرفتن آنها از بانک اطلاعاتی دریافت شوند و سرباری نیز تحمیل نشود.
ویوهای از قبل کامپایل شده
معمولا، هنگامی که از EF برای اولین بار استفاده مینمایید، ویوهایی ایجاد میگردد که برای ایجاد کوئریها مورد استفاده قرار میگیرند. این ویوها در طول حیات برنامه فقط یکبار ایجاد میشوند. ولی همین یکبار هم زمانبر هستند. خوشبختانه راههایی وجود دارد که ایجاد این ویوها را در زمان runtime انجام نداد و آن راه، استفاده از ویوهای از پیش کامپایل شده است. یکی از راههای ایجاد این ویوها استفاده از Entity Framework Power Tools است. بعد از نصب اکستنشن، بر روی فایل کانتکست راست کلیک کرده و سپس گزینهی Generate Views را از منوی Entity Framework انتخاب کنید.
توجه داشته باشید که هر تغییری را بعد از ایجاد این ویوها بر روی کانتکست اعمال نمایید، باید آنها را مجددا تولید کنید. برای آشنایی بیشتر با این ویوها به این لینک مراجعه کنید. هم چنین پکیج نیوگتی بنام EFInteractiveViews نیز برای این منظور تهیه و توزیع شده است.
حذف کوئریهای ابتدایی غیر ضروری
در هنگام شروع به کار با EF، چندین کوئری آغازین بر روی دیتابیس اجرا میشوند. یکی از کوئریهای آغازین جهت تشخیص نسخهی دیتابیس است که همانطور در تصویر زیر مشاهده میکنید، در حدود چند میلی ثانیه میباشد.
با توجه به توضیحات، در صورتیکه اطلاعی از نسخهی دیتابیس دارید، میتوانید این کوئری ابتدایی را تحریف نمایید. برای اینکار میتوان توسط متد ()ResolveManifestToken کلاسی که اینترفیس IManifestTokenResolver را پیاده سازی کرده است، نسخهی دیتابیس را برگردانیم و از یک رفت و برگشت به دیتابیس جلوگیری نماییم.
public class CustomManifestTokenResolver : IManifestTokenResolver { public string ResolveManifestToken(DbConnection connection) { return "2014"; } }
public class CustomDbConfiguration : DbConfiguration { public CustomDbConfiguration() { SetManifestTokenResolver(new CustomManifestTokenResolver()); } }
تخریب کانتکست
تخریب و از بین بردن کانتکست هنگامی که به آن نیاز نداریم بسیار ضروری است. یکی از روشهای اصولی برای Disposing کانتکست، محصور کردن آن بوسیله دستور Using است (البته فرض بر این است که قرار نیست از الگوهای اشاره شده استفاده نماییم). در صورت عدم تخریب صحیح کانتکست باید منتظر آسیب جدی به کارایی Garbage Collector جهت آزاد سازی منابع مورد استفاده کانتکست و هم چنین باز نمودن اتصالات جدید به دیتابیس باشید.
پاسخگویی به چندین درخواست بر روی یک کانکشن
EF از قابلیتی بنام Multiple Result Sets میتواند بهره ببرد که این قابلیت باعث میشود بر روی یک کانکشن ایجاد شده، یک یا چند درخواست از دیتابیس ارسال و یا دریافت شود که سبب کاهش تعداد رفت و برگشت به دیتابیس میشود. کاربرد دیگر این قابلیت، زمانی است که تاخیر زیادی (latency) بین اپلیکیشن و دیتابیس وجود دارد.
برای فعالسازی کافی است مقدار زیر را در کانکشن استرینگ اضافه نمایید:
MultipleActiveResultSets=True;
استفاده از متدهای ناهمگام
در C#5 و EF6 پشتیبانی خوبی از متدهای ناهمگام فراهم شده است و اکثر متدهایی مانند ToListAsync, CountAsync, FirstAsync, SaveChangesAsync و غیره که باعث رفت و برگشت به دیتابیس میشوند امکان پشتیبانی ناهمگام را نیز دارند. البته این قابلیت برای برنامههای یک درخواست در یک زمان شاید مفید نباشد؛ ولی برای برنامههای وبی برعکس. در برنامه وب جهت پشتیبانی از بارگذاری همزمان (concurrent) قابلیت ناهمگام (Async) سبب خواهد شد منابع تا زمان اجرای کوئری به ThreadPool بازگردانده شود و برای سرویس دهی مهیا باشند که باعث افزایش scalability خواهد شد.
بررسی و آزمایش با دادههای واقعی
در اکثر مواقع کارآیی با حجیم شدن دادهها کاهش پیدا میکند (البته در صورت عدم رعایت اصول استاندارد). بنابراین بررسی کارآیی در محیط هایی با حجم دادههای بالا ضروری است. هیچ چیز بدتر از آن نیست که همه چیز در محیط توسعه خوب و بی نقص باشد ولی در محیط عملیاتی به شکست بیانجامد. به همین جهت سعی کنید از ابزارهای تولید داده (^ و ^ و ^) برای ایجاد دادههای آزمایشی استفاده نمایید. سپس کارآیی کوئری خود را مورد بررسی و آزمایش قرار دهید.
SFDown
لطفا این سایت را فنی نگه دارید؛ هستند هزاران هزار سایت عمومی.