مطالب
چگونه کد قابل تست بنویسیم - قسمت دوم و پایانی
گام 3 – از بین بردن ارتباط لایه‌ها (Loose Coupling)
بجای استفاده از اشیاء واقعی، براساس interface‌ها برنامه نویسی کنید. اگر شما کد خود را با استفاده از IShoppingCartService  به عنوان یک interface بجای استفاده از شیء واقعی ShoppingCartService نوشته باشید، زمانیکه تست را مینویسید، میتوانید یک سرویس کارت خرید جعلی (mocking) که IShoppingCartService را پیاده سازی کرده جایگزین شیء اصلی نمایید. در کد زیر، توجه کنید تنها تغییر این است که متغیر عضو اکنون از نوع IShoppingCartService  است بجای ShoppingCartService .
public interface IShoppingCartService
{
    ShoppingCart GetContents();
    ShoppingCart AddItemToCart(int itemId, int quantity);
}
public class ShoppingCartService : IShoppingCartService
{
    public ShoppingCart GetContents()
    {
        throw new NotImplementedException("Get cart from Persistence Layer");
    }
    public ShoppingCart AddItemToCart(int itemId, int quantity)
    {
        throw new NotImplementedException("Add Item to cart then return updated cart");
    }
}
public class ShoppingCart
{
    public List<product> Items { get; set; }
}
public class Product
{
    public int ItemId { get; set; }
    public string ItemName { get; set; }
}
public class ShoppingCartController : Controller
{
    //Concrete object below points to actual service
    //private ShoppingCartService _shoppingCartService;
    //loosely coupled code below uses the interface rather than the 
    //concrete object
    private IShoppingCartService _shoppingCartService;
    public ShoppingCartController()
    {
        _shoppingCartService = new ShoppingCartService();
    }
    public ActionResult GetCart()
    {
        //now using the shared instance of the shoppingCartService dependency
        ShoppingCart cart = _shoppingCartService.GetContents();
        return View("Cart", cart);
    }
    public ActionResult AddItemToCart(int itemId, int quantity)
    {
        //now using the shared instance of the shoppingCartService dependency
        ShoppingCart cart = _shoppingCartService.AddItemToCart(itemId, quantity);
        return View("Cart", cart);
    }
}

گام 4 – وابستگی‌ها را تزریق کنید
اکنون ما تمام وابستگی‌ها را در یک جا مرکزیت داده‌ایم و کد ما رابطه کمی با آن وابستگی‌ها دارد. همانند گذشته، چندین راه برای پیاده سازی این گام وجود دارد. بدون استفاده از ابزارهای کمکی برای این مفهوم، ساده‌ترین راه دوباره نویسی (Overload) متد ایجاد کننده است:
//loosely coupled code below uses the interface rather 
//than the concrete object
private IShoppingCartService _shoppingCartService;
//MVC uses this constructor 
public ShoppingCartController()
{
    _shoppingCartService = new ShoppingCartService();
}
//You can use this constructor when testing to inject the    
//ShoppingCartService dependency
public ShoppingCartController(IShoppingCartService shoppingCartService)
{
    _shoppingCartService = shoppingCartService;
}

گام 5 – تست را با استفاده از یک شیء جعلی (Mocking) انجام دهید
مثالی از یک سناریوی تست ممکن در زیر آمده است. توجه کنید که یک شیء جعلی از نوع کلاس ShoppingCartService ساخته‌ایم. این شیء جعلی فرستاده می‌شود به شیء Controller و متد GetContents پیاده سازی میشود تا بجای آنکه کد اصلی را که به منبع داده مراجعه می‌کند اجرا نماید، داده‌های جعلی و شبیه سازی شده را برگرداند. بدلیل آنکه تمام کد را نوشته ایم، بسیار سریعتر از اجرای کوئری بر روی دیتابیس اجرا خواهد شد و دیگر نگرانی بابت تهیه داده تستی و یا تصحیح داده بعد از اتمام تست (بازگرداندن داده به حالت قبل از تست) نخواهم داشت. توجه داشته باشید که بدلیل مرکزیت دادن به وابستگی‌ها در گام 2 ، تنها باید یکبار آنرا تزریق نماییم و بخاطر کاری که در گام 3 انجام شد، وابستگی ما به حدی پایین آمده که میتوانیم هر شیء‌ایی  را  (جعلی و یا حقیقی) ارسال کنیم و فقط کافیست شیء مورد نظر IShoppingCartService را پیاده سازی کرده باشد.
[TestClass]
public class ShoppingCartControllerTests
{
    [TestMethod]
    public void GetCartSmokeTest()
    {
        //arrange
        ShoppingCartController controller = 
           new ShoppingCartController(new ShoppingCartServiceStub());
        // Act
        ActionResult result = controller.GetCart();
        // Assert
        Assert.IsInstanceOfType(result, typeof(ViewResult));
    }
}
/// <summary>
/// This is is a stub of the ShoppingCartService
/// </summary>
public class ShoppingCartServiceStub : IShoppingCartService
{
    public ShoppingCart GetContents()
    {
        return new ShoppingCart
        {
            Items = new List<product> {
                new Product {ItemId = 1, ItemName = "Widget"}
            }
        };
    }
    public ShoppingCart AddItemToCart(int itemId, int quantity)
    {
        throw new NotImplementedException();
    }
}

مطالب تکمیلی
از یک ابزار کنترل وابستگی (IoC/DI) استفاده کنید:
از رایج‌ترین و عمومی‌ترین ابزارهای کنترل وابستگی برای .Net می‌توان به StructureMap و CastleWindsor اشاره کرد. در کد نویسی واقعی، شما وابستگی‌های بسیاری خواهید داشت، که این وابستگی‌ها هم وابستگی هایی دارند که به سرعت از مدیریت شما خارج خواهند شد. راه حل این مشکل استفاده از یک ابزار کنترل وابستگی خواهد بود.
از یک چارچوب تجزیه (Isolation Framework) استفاده نمایید:
برای ایجاد اشیاء جعلی ممکن است کار زیادی لازم باشد و  استفاده از یک Isolation Framework میتواند زمان و میزان کد نویسی شمارا کم کند. از رایج‌ترین این ابزارها میتوان Rhino Mocks  و Moq را نام برد.
مطالب
فعال سازی Multicore JIT
Multicore JIT یکی از قابلیت‌های کلیدی در دات نت 4.5 می‌باشد که در واقع راه حلی برای بهبود سرعت اجرای برنامه‌های دات نتی است. قبل از معرفی این قابلیت ابتدا اجازه دهید نحوه کامپایل یک برنامه دات نتی را بررسی کنیم.
انواع compilation
در حالت کلی دو نوع فرآیند کامپایل داریم:
  • Explicit
در این حالت دستورات قبل از اجرای برنامه به زبان ماشین تبدیل می‌شوند. به این نوع کامپایلرها AOT یا Ahead Of Time گفته می‌شود. این نوع از کامپایلرها برای اطمینان از اینکه CPU بتواند قبل از انجام تعاملی تمام خطوط کد را تشخیص دهد، طراحی شده اند.
  • Implicit
این نوع compilation به صورت دو مرحله ایی صورت می‌گیرد. در اولین قدم سورس کد توسط یک کامپایلر به یک زبان سطح میانی(IL) تبدیل می‌شود. در مرحله بعدی کد IL به دستورات زبان ماشین تبدیل می‌شوند. در دات نت فریم ورک به این کامپایلر JIT یا Just-In-Time گفته می‌شود.
در حالت دوم قابلیت جابجایی برنامه به آسانی امکان پذیر است، زیرا اولین قدم از فرآیند به اصطلاح platform agnostic می‌باشد، یعنی قابلیت اجرا بر روی گستره وسیعی از پلت فرم‌ها را دارد.

کامپایلر JIT
JIT بخشی از Common Language Runtime یا CLR می‌باشد. CLR در واقع وظیفه مدیریت اجرای تمام برنامه‌های دات نتی را برعهده دارد.

همانطور که در تصویر فوق مشاهده می‌کنید، سورس کد توسط کامپایلر دات نت به exe و یا dll کامپایل می‌شود. کامپایلر JIT تنها متدهایی را که در زمان اجرا(runtime) فراخوانی می‌شوند را کامپایل می‌کند. در دات نت فریم ورک سه نوع JIT Compilation داریم:

Normal JIT Compilation   

در این نوع کامپایل، متدها در زمان فراخوانی در زمان اجرا کامپایل می‌شوند. بعد از اجرا، متد داخل حافظه ذخیره می‌شود. به متدهای ذخیره شده در حافظه jitted گفته می‌شود. دیگر نیازی به کامپایل متد jit شده نیست. در فراخوانی بعدی، متد مستقیماً از حافظه کش در دسترس خواهد بود.

Econo JIT Compilation 

این نوع کامپایل شبیه به حالت Normal JIT است با این تفاوت که متدها بلافاصله بعد از اجرا از حافظه حذف می‌شوند.

Pre-JIT Compilation 

یکی دیگر از حالت‌های کامپایل برنامه‌های دات نتی Pre-JIT Compilation می باشد. در این حالت به جای متدهای مورد استفاده، کل اسمبلی کامپایل می‌شود. در دات نت می‌توان اینکار را توسط Ngen.exe یا (Native Image Generator) انجام داد. تمام دستورالعمل‌های CIL قبل از اجرا به کد محلی(Native Code) کامپایل می‌شوند. در این حالت runtime می‌تواند از native images به جای کامپایلر JIT استفاده کند. این نوع کامپایل عملیات تولید کد را در زمان اجرای برنامه به زمان Installation منتقل می‌کند، در اینصورت برنامه نیاز به یک Installer برای اینکار دارد.

Multicore JIT

در دات نت فریم ورک 4.5 یک راه حل جایگزین دیگر برای بهینه سازی و بهبود سرعت اجرای برنامه‌های دات نت وجود دارد. همانطور که عنوان شد Ngen.exe برای در دسترس بودن نیاز به Installer برای برنامه دارد. توسط Multicore JIT متدها بر روی دو هسته به صورت موازی کامپایل می‌شوند، در اینصورت می‌توانید تا 50 درصد از JIT Time صرفه جویی کنید.

Multicore JIT همچنین می‌تواند باعث بهبود سرعت در برنامه‌های WPF شود. در نمودار زیر می‌توانید حالت‌های استفاده و عدم استفاده از Multicore JIT را در سه برنامه WPF نوشته شده مشاهده کنید.

Multicore JIT در عمل

Multicore JIT از دو مد عملیاتی استفاده می‌کند: مد ثبت(Recording mode)، مد بازپخش(Playback mode)

در حالت ثبت کامپایلر JIT هر متدی که نیاز به کامپایل داشته باشد را رکورد می‌کند. بعد از اینکه CLR تعیین کند که اجرای برنامه به اتمام رسیده است، تمام متدهایی که اجرا شده اند را به صورت یک پروفایل بر روی دیسک ذخیره می‌کند.

هنگامیکه Multicore JIT فعال می‌شود، با اولین اجرای برنامه، حالت ثبت مورد استفاده قرار می‌گیرد. در اجراهای بعدی، از حالت بازپخش استفاده می‌شود. حالت بازپخش پروفایل را از طریق دیسک بارگیری کرده، و قبل از اینکه این اطلاعات توسط ترد اصلی مورد استفاده قرار گیرد، از آنها برای تفسیر (کامپایل) متدها در پیش‌زمینه استفاده می‌کند. 

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

استفاده از Multicore JIT

در برنامه‌های 4.5 ASP.NET و 5 Silverlight به صورت پیش فرض این ویژگی فعال می‌باشد. ازآنجائیکه این برنامه‌ها hosted application هستند؛ در نتیجه فضای مناسبی برای ذخیره سازی پروفایل در این نوع برنامه‌ها موجود می‌باشد. اما برای برنامه‌های Desktop این ویژگی باید فعال شود. برای اینکار کافی است دو خط زیر را به نقطه شروع برنامه تان اضافه کنید:

public App() 
{
    ProfileOptimization.SetProfileRoot(@"C:\MyAppFolder");
    ProfileOptimization.StartProfile("Startup.Profile");
}

توسط متد SetProfileRoot می‌توانیم مسیر ذخیره سازی پروفایل JIT را مشخص کنیم. در خط بعدی نیز توسط متد StartProfile نام پروفایل را برای فعال سازی Multicore JIT تعیین می‌کنیم. در این حالت در اولین اجرای برنامه پروفایلی وجود ندارد، Multicore JIT در حالت ثبت عمل می‌کند و پروفایل را در مسیر تعیین شده ایجاد می‌کند. در دومین بار اجرای برنامه CRL پروفایل را از اجرای قبلی برنامه بارگذاری می‌کند؛ در این حالت Multicore JIT به صورت بازپخش عمل می‌کند.

همانطور که عنوان شد در برنامه‌های ASP.NET 4.5 و Silverlight 5 قابلیت Multicore JIT به صورت پیش فرض فعال می‌باشد. برای غیر فعال سازی آن می‌توانید با تغییر فلگ profileGuidedOptimizations به None اینکار را انجام دهید:

<?xml version="1.0" encoding="utf-8" ?> 
<configuration>
 <!-- ... -->
 <system.web> 
 <compilation profileGuidedOptimizations="None" /> 
 <!-- ... --> 
 </system.web> 
</configuration>
مطالب
آشنایی بیشتر با AngularJS Directive

در مطلب آشنایی با Directive‌ها در AngularJS با نحوه‌ی ایجاد Directive آشنا شدیم. هدف از این مطلب، آشنایی بیشتر با Directive در AngularJS است؛ یکی از بهترین فریم ورک‌های جاوااسکریپتی، با قابلیت ایجاد کتابخانه‌هایی از کامپوننت‌ها که می‌توانند به HTML اضافه شوند .

کتابخانه‌های جاوااسکریپتی زیادی وجود دارند. به عنوان مثال Bootstrap یکی از محبوب‌ترین "front-end framework" ها است که امکان تغییر در ظاهر المنت‌ها را فراهم می‌کند و شامل تعدادی کامپوننت جاوااسکریپتی نیز می‌باشد. مشکل کار، در هنگام استفاده از کامپوننت ها است. شخصی که در حال توسعه‌ی HTML است باید در کد جاوااسکریپتی خود از  jQuery استفاده کند و بعنوان مثال یک Popover  را فعال یا غیر فعال کند و این، یک فرآیند خسته کننده و مستعد خطا است. 


یک مثال ساده از Directives AngularJS و بررسی آن

var m = angular.module("myApp");
 
myApp.directive("myDir", function() {
  return {
  restrict: "E",   
  scope: {     
   name: "@",   
   amount: "=",  
   save: "&"    
  },
  template:    
   "<div>" +
   "  {{name}}: <input ng-model='amount' />" +
   "  <button ng-click='save()'>Save</button>" +
   "</div>",
  replace: true,   
  transclude: false, 
  controller: [ "$scope", function ($scope) { …  }],
  link: function (scope, element, attrs, controller) {…}
  }
});

به الگوی نامگذاری directive دقت کنید. پیشوند my شبیه به یک namespace است. بنابراین اگر یک Application از دایرکتیوهای قرار گرفته در Module ‌های متفاوت استفاده کند، به راحتی می‌توان محل تعریف یک directive را تشخیص داد. این نام می‌تواند نشان دهنده‌ی این باشد که این directive را خودتان توسعه داده‌اید یا از یک directive توسعه داده شده توسط شخص دیگری در حال استفاده هستید. به هر حال این نحوه‌ی نام گذاری یک اجبار نیست و به عنوان یک پیشنهاد است.

سازنده directive یک شیء را با تعدادی خاصیت باز می‌گرداند که تمامی آنها در سایت AngularJS توضیح داده شده‌اند. در اینجا قصد داریم تا توضیحی مختصر در مورد کاری که این خصوصیات انجام می‌دهند داشته باشیم.

· restrict : تشخیص می‌دهد که آیا directive در HTML استفاده خواهد شد. گزینه‌های قابل استفاده ‘A’ ،  ‘E’ ، ‘C’ برای attribute ، element ، class و یا comment است . پیش فرض ‘A’ برای attribute است. اما ما بیشتر علاقه به استفاده از ویژگی element برای ایجاد المنت‌های UI داریم.

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

-   name: "@" (by value, one-way) : علامت @ مشخص می‌کند که مقدار متغیر ارسال می‌شود. Directive یک رشته را دریافت می‌کند که شامل مقدار ارسال شده از scope پدر می‌باشد. Directive می‌تواند از آن استفاده کند، اما نمی‌تواند مقدار آن را در scope پدر تغییر دهد.

-   amount: "=" (by reference, two-way) : علامت = مشخص می‌کند این متغیر با ارجاع ارسال می‌شود. Directive یک ارجاع به مقدار متغیر در scope اصلی دریافت می‌کند. مقدار می‌تواند هر نوع داده ای، شامل یک شیء complex یا یک آرایه باشد. Directive می‌تواند مقدار را در scope پدر تغییر دهد. این نوع متغیر، زمانیکه نیاز باشد directive مقدار را در scope پدر تغییر دهد، استفاده می‌شود.

-   save: "&" (expression) : علامت & مشخص می‌کند این متغیر یک expression را که در scope پدر اجرا می‌شود، نگهداری می‌کند. اکنون directive قابلیت انجام کارهایی فراتر از تغییر یک مقدار را دارد. به عنوان مثال می‌توان یک تابع را از scope پدر فراخوانی و نتیجه‌ی اجرا را دریافت کرد.

· template :  الگوی رشته ای که جایگزین المنت تعریف شده می‌شود. فرآیند جایگزینی تمامی خصوصیات را از المنت قدیمی به المنت جدید انتقال می‌دهد. به نحوه استفاده از متغیر‌های تعریف شده در scope ایزوله دقت کنید. این مورد به شما امکان تعریف directive های macro-style را می‌دهد که نیاز به کد اضافه‌ای، ندارند. اگرچه در بیشتر موارد الگو  یک تگ ساده <div> است که از کد‌های link که در زیر توضیح داده شده است استفاده می‌کند.

· replace : تعیین می‌کند که آیا الگوی directive باید جایگزین المنت شود. مقدار پیش فرض false است.

· transclude : تعیین کننده این است که محتوای directive باید در المنت کپی شود یا خیر. در مثال زیر المنت tab شامل المنت‌های HTML دیگر است پس transclude برابر true است.  

<body ng-app="components">
  <h3>BootStrap Tab Component</h3>
    <tabs>
       <pane title="First Tab">
          <div>This is the content of the first tab.</div>
       </pane>
       <pane title="Second Tab">
          <div>This is the content of the second tab.</div>
       </pane>
    </tabs>
</body>
 

· link : این تابع بیشتر منطق directive را شامل می‌شود. Link وظیفه دستکاری DOM ، ایجاد event listener ‌ها و... را دارد. تابع Link پارامترهای زیر را دریافت می‌کند:

-   scope : ارجاع به scope ایزوله شده directive دارد.

-   element : ارجاع به المنت‌های DOM که directive را تعریف کرده اند. تابع link معمولا برای دستکاری المنت از jQuery استفاده می‌کند. (یا از Angular's jqLite در صورتی که jQuery بارگذاری نشده باشد)

-   controller : در مواقعی که از دایرکتیو‌های تو در تو استفاده می‌شود کاربرد دارد. این پارامتر یک directive فرزند با ارجاعی به پدر را فراهم می‌کند، بنابراین موجب ارتباط  directive ‌ها می‌شود.

به عنوان مثال،  این directive  که پیاده سازی bootstrap tab را انجام داده است، می‌توانید مشاهده نمایید.

موفق باشید

مطالب
خلاص شدن از شر deep null check
آیا تا به حال مجبور به نوشتن کدی شبیه قطعه کد زیر شده اید؟ 
var store = GetStore();
string postCode = null;
if (store != null && store.Address != null && store.Address.PostCode != null)
     postCode = store.Address.PostCode.ToString();

بله! من مطمئن هستم برای شما هم پیش آمده است.
هدف بازیابی و یا محاسبه یک مقدار است، اما برای انجام این کار می‌بایست به چندین شیء میانی دسترسی پیدا کنیم که البته  ممکن است در حالت پیش فرض خود قرار داشته باشند و حاوی هیچ مقداری نباشند. بنابراین برای جلوگیری از وقوع NullException ، مجبوریم تمامی اشیائی که در مسیر قرار دارند را بررسی کنیم که null نباشند. مثال بالا کاملا گویا ست. گاهی اوقات حتی ممکن است فراخوانی یک متد، تبدیل نوع با استفاده از as و یا دسترسی به عناصر یک مجموعه وجود داشته باشد. متاسفانه مدیریت تمامی این حالات باعث حجیم شدن کد‌ها و در نتیجه کاهش خوانایی آنها می‌شود. بنابراین باید به دنبال یک راه حل مناسب بود.

   
استفاده از یک متد الحاقی شرطی (Conditional extensions)

از نظر بسیاری از برنامه نویس‌ها راه حل، استفاده از یک متد الحاقی شرطی است. اگر عبارت "c# deep null check" را گوگل کنید، پیاده سازی‌های متنوعی را پیدا خواهید کرد. اگر چه  این متد‌ها نام‌های متفاوتی دارند اما همه آن‌ها از یک ایده کلی مشترک استفاده می‌کنند:
public static TResult IfNotNull<TResult, TSource>(
    this TSource source,
    Func<TSource, TResult> onNotDefault)
    where TSource : class
{
    if (onNotDefault == null) throw new ArgumentNullException("onNotDefault");
    return source == null ? default(TResult) : onNotDefault(source);
}
همانطور که می‌بینید این متد الحاقی مقداری از نوع TResult را بر می‌گرداند.  اگر source که در اینجا با توجه به الحاقی بودن متد به معنای شی جاری است، null باشد  مقدار پیش فرض نوع خروجی(TResult) بازگردانده می‌شود و در غیر این صورت دیلیگیت onNotDefault فراخوانی می‌گردد.
بعد از افزودن متد الحاقی IfNotNull به پروژه می‌توانیم مثال ابتدای مطلب را به صورت زیر بنویسیم :
var postCode =
    GetStore()
        .IfNotNull(x => x.Address)
        .IfNotNull(x => x.PostCode)
        .IfNotNull(x => x.ToString());

این روش مزایای بسیاری دارد اما در موارد پیچیده دچار مشکل می‌شویم. برای مثال در نظر بگیرید قصد داریم در طول مسیر، متدی را فراخوانی کنیم و مقدار بازگشتی را در یک متغیر موقتی ذخیره کنیم و بر اساس آن ادامه مسیر را طی کنیم. متاسفانه این کار‌ها هم اکنون امکان پذیر نیست. پس به نظر می‌رسد باید کمی متد الحاقی IfNotNull را بهبود ببخشیم.
برای بهبود عملکرد متد الحاقی IfNotNull علاوه بر موارد ذکر شده حداقل دو مورد به نظر من می‌رسد:
  • این متد فقط با انواع ارجاعی (reference types)  کار می‌کند و می‌بایست برای کار با انواع مقداری (value types) اصلاح شود.
  • با انواع داده ای مثل string چه باید کرد؟ در مورد این نوع داده‌ها تنها مطمئن شدن از null نبودن کافی نیست. برای مثال در مورد string ، گاهی اوقات ما می‌خواهیم از خالی نبودن آن نیز مطمئن شویم. و یا در مورد collection‌ها تنها null نبودن کافی نیست بلکه زمانی که نیاز به محاسبه مجموع و یا یافتن بزرگترین عضو است، باید از خالی نبودن مجموعه و وجود حداقل یک عضو در آن مطمئن باشیم.
برای حل این مشکلات می‌توانیم متد الحاقی IfNotNull را به متد الحاقی IfNotDefault تبدیل کنیم:
public static TResult IfNotDefault<TResult, TSource>(
    this TSource source,
    Func<TSource, TResult> onNotDefault,
    Predicate<TSource> isNotDefault = null)
{
    if (onNotDefault == null) throw new ArgumentNullException("onNotDefault");
    var isDefault = isNotDefault == null
        ? EqualityComparer<TSource>.Default.Equals(source, default(TSource))
        : !isNotDefault(source);
   return isDefault ? default(TResult) : onNotDefault(source);
}

تعریف این متد خیلی با تعریف متد قبلی متفاوت نیست. به منظور پشتیبانی از struct ها، قید where TSource : class حذف شده است. بنابراین دیگر نمی‌توان از مقایسه‌ی ساده null  با استفاده از عملگر == استفاده کرد چراکه struct‌ها nullable نیستند. پس مجبوریم از EqualityComparer<TSource>.Default بخواهیم که این کار را انجام دهد. متد الحاقی IfNotDefault همچنین شامل یک predicate اختیاری با نام isNotDefault  است. در صورتی که مقایسه پیش فرض کافی نبود می‌توان از این predicate استفاده کرد.
در انتها اجازه بدهید چند مثال کاربردی را مرور کنیم:
1- انجام یک سری اعمال بر روی string در صورتی که رشته خالی نباشد:
return person
        . IfNotDefault(x => x.Name)
        . IfNotDefault(SomeOperation, x => !string.IsNullOrEmpty(x));

محاسبه‌ی مقدار میانگین. متد الحاقی IfNotDefault به زیبایی در یک زنجیره‌ی LINQ کار می‌کند:
var avg = students
        .Where(IsNotAGraduate)
        .FirstOrDefault()
        .IfNotDefault(s => s.Grades) 
        .IfNotDefault(g => g.Average(), g => g != null && g.Length > 0);

برای مطالعه بیشتر 
Get rid of deep null checks
Chained null checks and the Maybe monad
Maybe or IfNotNull using lambdas for deep expressions
Dynamically Check Nested Values for IsNull Values
مطالب
ایجاد سرویس چندلایه‎ی WCF با Entity Framework در قالب پروژه - 5
پس از ایجاد متدها، نوبت به تغییرات App.Config می‎رسد. هرچند خود Visual Studio برای کلاس پیش‌گزیده‌ی خود تنظیماتی را در App.Config افزوده است ولی چنان‎چه در در خاطر دارید ما آن فایل‎ها را حذف کردیم و فایل‎های جدیدی به جای آن افزودیم. از این رو مراحل زیر را انجام دهید:
1- فایل App.Config را از Solution Explorer باز کنید.
2- به جای عبارت MyNewsWCFLibrary.Service1 در قسمت Service Name این عبارت را بنویسید: MyNewsWCFLibrary.MyNewsService
3- در قسمت BaseAddress عبارت Design_Time_Addresses را حذف کنید.
4- در قسمت BaseAddress شماره پورت را به 8080 تغییر دهید.
5- در قسمت BaseAddress به جای Service1 بنویسید: MyNewsService
6- در قسمت endpoint به جای عبارت MyNewsWCFLibrary.IService1 بنویسید: MyNewsWCFLibrary.IMyNewsService 
در پایان تگ Service در App.Config باید همانند کد زیر باشد:
   <services>
      <service name="MyNewsWCFLibrary.MyNewsService">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8080/MyNewsWCFLibrary/MyNewsService/" />
          </baseAddresses>
        </host>
        <!-- Service Endpoints -->
        <!-- Unless fully qualified, address is relative to base address supplied above -->
        <endpoint address="" binding="basicHttpBinding" contract="MyNewsWCFLibrary.IMyNewsService">
          <!-- 
              Upon deployment, the following identity element should be removed or replaced to reflect the 
              identity under which the deployed service runs.  If removed, WCF will infer an appropriate identity 
              automatically.
          -->
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
        <!-- Metadata Endpoints -->
        <!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. -->
        <!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
      </service>
    </services>
تغییرات را ذخیره کنید و پروژه را اجرا کنید. باید پنجره‌ای شبیه به پنجره‌ی زیر نشان داده شود:

در صورت مشاهده پیام خطا، ویژوال استودیو را ببندید و این‌بار به صورت Run as administrator باز کنید.

برای نمونه روی متد AddCategory کلیک کنید. در پنجره نشان داده شده همانند شکل در برابر فیلد CatName مقداری وارد کنید و روی دکمه Invoke کلیک کنید. متد مورد نظر اجرا شده و مقداری که وارد کرده ایم در پایگاه داده‌ها ذخیره می‌شود. مقداری که در قسمت پایین دیده می‌شود خروجی متد است که در اینجا شناسه رکورد درج‌شده است.

بار دیگر برای مشاهده رکورد درج‌شده روی متد GetAllCategory کلیک کنید. به علت این‌که این متد ورودی ندارد در قسمت بالا چیزی نشان داده نمی‌شود. روی دکمه Invoke کلیک کنید. با پیغام خطای زیر روبه‌رو خواهید شد:

افزودن ویژگی Virtual به tblNews و tblCategory در بخش دوم  خواندید؛ باعث می‌شود که Entity Framework در هنگام اجرا کلاس‌هایی با عنوان "پروکسی‌های پویا" به کلاس‌های Address و Customer بیفزاید و بنابراین قابلیت Lazy Loading برای این کلاس‌ها در زمان اجرای برنامه فراهم می‌گردد. 

ولی با افزودن پروکسی‌های پویا به کلاس‌های ما، این کلاس‌ها قابلیت انتقال خود از طریق سرویس‌های WCF را از دست می‌دهند زیرا پروکسی‌های پویا به طور پیش‌گزیده قابلیت سریالایز و دیسریالایز شدن را ندارند!

خوشبختانه می‌توانیم این ویژگی را در کلاس DBContext غیرفعال کنیم. برای این منظور قالب سازنده‌ی آن یا MyNewsModel.Context.tt را از Solution Explorer باز کنید و کد زیر را در آن پیدا کنید:

<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : DbContext
{
    public <#=code.Escape(container)#>()
        : base("name=<#=container.Name#>")
    {

سپس در ادامه‌ی آن کدغیرفعال‌کردن پروکسی پویا را به این شکل بنویسید:

<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : DbContext
{
    public <#=code.Escape(container)#>()
        : base("name=<#=container.Name#>")
    {
      Configuration.ProxyCreationEnabled = false;

اکنون اگر فایل را ذخیره کنیم سپس فایل MyNewsModel.Context.cs را از Solution Explorer باز کنید؛ خواهید دید که این خط کد در جای خود قرارگرفته است.

بار دیگر پروژه را اجرا کنید روی متد GetAllCategory کلیک کنید. این بار اگر دکمه Invoke را بفشارید با همانند شکل زیر را خواهید دید:

در بخش ششم پیرامون ارتباط جدول‌های tblNews و tblCategory و نمایش محتویات وابسته جدول خبر به دسته و تنظیمات آن در t4 و کلاس Service

در بخش هفتم پیرامون میزبانی WCFLibrary در یک Web Application

و در بخش هشتم پیرامون ایجاد یک برنامه‌ی ویندوزی جهت استفاده از سرویس‌های WCF خواهم نوشت. 

مطالب
ویژگی های آگهی استخدام مناسب همراه با نقدی بر یک آگهی استخدام
امروز فرصتی پیش آمد تا سری هم به بخش آگهی‌های این سایت بزنم. با یک آگهی استخدام (مربوط به شرکتی تحت عنوان فناوران سیستم دلفین) روبرو شدم که نظرم را جلب کرد. تقریبا مدت‌ها بود که با یک آگهی استخدام به این صورت روبرو نشده بودم. در رشته کامپیوتر و اغلب در بخش تولید و پشتیبانی نرم افزار کمتر با آگهی‌های استخدام این چنینی که کامل باشند(البته دارای ضعف هایی نیز بود) روبرو می‌شویم. تصمیم گرفتم در این پست به تشریح ویژگیهای یک آگهی استخدام خوب (همراه با نقدی بر این آگهی استخدام ) بپردازم. یک جمله معروف وجود دارد با این مضمون که، استخدام دو مرحله دارد:
  • جذب
  • انتخاب یا گزینش

مرحله جذب:

این مرحله مربوط است به آگهی استخدام و چگونگی تشریح مسایل و شرایط به گونه ای که فرد متقاضی را راغب به ارسال رزومه یا نمونه کار نماید. این مرحله مهم‌تر از مرحله انتخاب است؛ به دلیل اینکه اگر نتوانیم متقاضیان کار را جذب کنیم، دامنه انتخاب بین افراد متقاضی کاهش پیدا می‌کند و گاهی مجبور خواهیم شد بین گزینه‌های بد و بدتر، بد را انتخاب نماییم. 

مرحله انتخاب:

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

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

»ذکر نام شرکت

اولین مورد که در بسیاری از آگهی‌های استخدام رعایت نمی‌شود عدم ذکر نام شرکت است. دیده می‌شود در آگهی‌ها بیشتر از عناوینی نظیر "یک شرکت معتبر نرم افزاری" یا "یک شرکت فعال در زمینه تولید نرم افزار" و... استفاده می‌کنند. ذکر نام شرکت از آن جهت مهم است که فرد متقاضی می‌تواند با یک جستجوی ساده در اینترنت (در صورتی که شرکت تقاضا دهنده یک وب سایت مناسب در این زمینه داشته باشد) بسیاری از اطلاعات مهم نظیر زمینه فعالیت شرکت ، مشتریان عمده شرکت ، محصولات تولید شده قبلی یا حتی آدرس شرکت (برای بررسی وضعیت رفت و آمد) را به دست بیاورد. در آگهی استخدام ذکر شده این مورد به خوبی رعایت شده بود.

»ذکر آدرس و شماره تماس:

دلیل اصلی برای ذکر آدرس شرکت صرفا برای بررسی وضعیت رفت و آمد از نظر شرایط ترافیک شهری و بعد مسافت یا حتی شرایط رفت و آمد با خودروی شخصی است که برای بیشتر متقاضیان مهم است. در آگهی بالا نیز این مورد رعایت شده بود.

» ذکر شرایط استخدام

موردی که در آگهی بالا نظرم را جلب کرد تشریح کامل شرایطی بود که متقاضیان باید آن را داشته باشند. برای مثال ذکر شرایط سنی، شرایط مربوط به عدم اشتغال به تحصیل در دانشگاه‌ها یا موسسات یا حتی شرایط مربوط به اخراج از دانشگاه ها. در این صورت برخی از متقاضیان ولو اندک در همین ابتدا فیلتر می‌شوند.

»ذکر شرایط تخصصی متقاضیان کار:

در بخش به صورت کامل شرایط تخصصی و مهارتی افراد مورد بررسی قرار گرفته بود. در یک نگاه خوب به نظر می‌رسید ولی اگر با دقت به این بخش نگاه کنید متوجه خواهید شد به دلیل عدم نگارش صحیح موارد مورد نیاز، کمتر کسی دارای این همه توانایی است آن هم به صورت تسلط کامل. استفاده از واژه تسلط کامل باید با احتیاط انجام شود. برای مثال تسلط کامل بر VB.NET , C#.NET Windows Application . بهتر بود از یا استفاده می‌شد. به این صورت " تسلط بر VB.NET یا C#.NET  در Windows Application"

» ذکر اولویت ها

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

»ذکر آدرس وب سایت شرکت:

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

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

»عدم توازن بین عنوان آگهی با محتوای آن :

در عنوان آگهی ذکر شده بود "برنامه نویس تحت وب" در حالی که در شرایط تخصصی، موردی به عنوان تسلط کامل بر برنامه نویس تحت ویندوز ذکر شده  آن هم با دو زبان Vb.Net و C#.Net

آیا منظور از تسلط کامل بر مدیریت بانک اطلاعاتی SqlServer همان DBA است؟ اگر پاسخ مثبت است در این صورت چند نفر واجد شرایط را می‌توان پیدا کرد که هم در سطح DBA باشند و هم در سطح یک برنامه نویس سطح بالا؟ اگر پاسخ منفی است بهتر بود از واژه داشتن تجربه در زمینه مدیریت بانک اطلاعاتی یا حتی آشنایی با مدیریت بانک‌های اطلاعاتی استفاده می‌شد.

مورد دیگری که تا حدودی باعث سردرگمی می‌شد این است که نیاز به تسلط کامل به Asp.Net Web Form و هم چنین به Asp.Net MVC است. چرا هردو، آن هم در سطح تسلط کامل؟

در بخش اولویت‌ها موردی ذکر شد با عنوان آشنایی با کامپوننت‌های برنامه نویسی نظیر DevExpress و Telerik  و Kendo. آیا منظور آشنایی با تمام این موارد بوده است یا فقط یکی از آن ها؟

یک ضعف بزرگ که در اغلب آگهی‌ها (از جمله در این آگهی نیز) وجود دارد، عدم ذکر شرایط شرکت برای متقاضیان است. بهتر بود بعد از ذکر این همه شرایط برای متقاضیان  و برنامه نوسان، کمی هم درباره وضعیت حقوق و مزایا (برای مثال ذکر حداقل حقوق) و بیمه یا حتی شرایط رفاهی و خاص در نظر گرفته شده (که البته با توجه به وضعیت فعلی که دریافت حقوق ماهانه بدون تاخیر یک موهبت است این مورد بیشتر شبیه به رویا برای برنامه نویسان خواهد بود) صحبت می‌شد. 

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

مطالب
آموزش TypeScript #1
با گسترش روز افزون زبان برنامه نویسی Javascript و استفاده هر چه بیشتر آن در تولید برنامه‌های تحت وب این زبان به یکی از قدرت‌های بزرگ در تولید برنامه‌های مبتنی بر وب تبدیل شده است. ترکیب این زبان با Css و Html5 تقریبا هر گونه نیاز برای تهیه و توسعه برنامه‌های وب را حل کرده است. جاوا اسکریپت در ابتدا برای اسکریپت نویسی سمت کلاینت برای صفحات وب ایجاد شد و برای سال‌ها به‌عنوان ابزاری برای مدیریت کردن رویدادهای صفحات وب محدود شده بود  و در نتیجه بسیاری از امکانات لازم برای برنامه‌نویسی برنامه‌های مقیاس بزرگ را به‌همراه نداشت. امروزه به قدری Javascript  توسعه داده شده است که حتی در تولید برنامه‌های Native مانند Windows Store  و برنامه‌های تحت Cloud نیز استفاده می‌شود. پیشرفت‌های صورت گرفته و اشاره شده در این حوزه موجب شد تا شاهد پیداش برنامه‌های مبتنی بر جاوا اسکریپت با سایزهای بی سابقه‌ای باشیم و این بیانگر این بود که تولید برنامه‌های مبتنی بر جاوا اسکریپت در مقیاس‌های بزرگ امر دشواری است و اینک TypeScript توسط غول نرم افزاری جهان پا به عرصه گذاشته که این فرآیند را آسان‌تر نماید. به کمک TypeScript می‌توان برنامه تحت JavaScript در مقیاس بزرگ تولید کرد به طوری با هر مرورگر و سیستم عاملی سازگار باشد. TypeScript از شی گرایی نیز پشتیبانی می‌کند و خروجی آن در نهایت به JavaScript کامپایل می‌شود. خیلی‌ها عقیده دارند که هدف اصلی مایکروسافت از تولید و توسعه این زبان رقابت با CoffeeScript است.  CoffeeScript یک زبان متن باز است که در سال 2009 توسط Jeremy Ashkenas ایجاد شده است و سورس آن در GitHub موجود می‌باشد. در آینده، بیشتر به مباحث مربوط به CoffeeScript و آموزش آن خواهم پرداخت.

در تصویر ذیل یک مقایسه کوتاه بین CoffeeScript و TypeScript را مشاهده می‌کنید.

با TypeScript چه چیزهایی به دست خواهیم آورد؟

یک نکته مهم این است که این زبان به خوبی در Visual Studio پشتیبانی می‌شود و قابلیت Intellisense نوشتن برنامه به این زبان را دلپذیرتر خواهد کرد و از طرفی دیگر به نظر من یکی از مهم‌ترین مزیت هایی که TypeScript در اختیار ما قرار می‌دهد این است که می‌توانیم به صورت Syntax آشنای شی گرایی کد نویسی کنیم و خیلی راحت‌تر کد‌های خود را سازمان دهی کرده و از نوشتن کد‌های تکراری اجتناب کنیم.

یکی دیگر از مزیت‌های مهم این زبان این است که این زبان از Static Typing به خوبی پشتیبانی می‌کند. این بدین معنی است که شما ابتدا باید متغیر‌ها را تعریف کرده و نوع آن‌ها را مشخص نمایید و هم چنین در هنگام پاس دادن مقادیر به پارامتر‌های توابع باید حتما به نوع داده ای آن‌ها دقت داشته باشید چون کامپایلر بین انواع داده ای در TypeScript تمایز قایل است و در صورت رعایت نکردن این مورد شما با خطا مواجه خواهید شد. این تمایز قایل شدن باعث می‌شود که برنامه هایی خواناتر داشته باشیم از طرفی باعث می‌شود که خطا یابی و نوشتن تست برای برنامه راحت‌تر و تمیزتر باشد. بر خلاف JavaScript، در TypeScript(به دلیل پشتیبانی از شی گرایی) می‌توانیم علاوه بر داشتن کلاس، اینترفیس نیز داشته باشیم و در حال حاضر مزایای استفاده از اینترفیس بر کسی پوشیده نیست.

به دلیل اینکه کد‌های TypeScript ابتدا کامپایل شده و بعد تبدیل به کد‌های JavaScript می‌شوند در نتیجه قبل از رسیدن به مرحله اجرای پروژه، ما از خطاهای موجود در کد خود مطلع خواهیم شد.

البته این نکته را نیز فراموش نخواهیم کرد که این زبان تازه متولد شده است(سال 2012 توسط Anders Hejlsberg) و همچنان در حال توسعه است و این در حال حاضر مهم‌ترین عیب این زبان می‌تواند باشد چون هنوز به پختگی سایر زبان‌های اسکریپتی در نیامده است.

در ذیل یک مثال کوچک به زبان TypeScript و JavaScript را برای مقایسه در خوانایی و راحتی کد نویسی قرار دادم:

TypeScript:

class Greeter {
    greeting: string;

    constructor (message: string) {
        this.greeting = message;
    }

    greet() {
        return "Hello, " + this.greeting;
    }
}
بعد از کامپایل کد بالا به کدی معادل زیر در JavaScript تبدیل خواهد شد:
var Greeter = (function () {
    function Greeter(message) {
        this.greeting = message;
    }
    Greeter.prototype.greet = function () {
        return "Hello, " + this.greeting;
    };
    return Greeter;
})();
توضیح چند واژه در TypeScript

Program : یک برنامه TypeScript مجموعه ای از یک یا چند Source File است. این Source File‌ها شامل کد‌های پیاده سازی برنامه هستند ولی در خیلی موارد برای خوانایی بیشتر برنامه می‌توان فقط تعاریف را در این فایل‌های سورس قرار داد.
Module: ماژول در TypeScript شبیه به مفاهیم فضای نام یا namespace در دات نت است و می‌تواند شامل چندین کلاس یا اینترفیس باشد.
Class : مشابه به مفاهیم کلاس در دات نت است و دقیقا همان مفهوم را دارد. یک کلاس می‌تواند شامل چندین تابع و متغیر با سطوح دسترسی متفاوت باشد. در TypeScript مجاز به استفاده از کلمات کلیدی public و private نیز می‌باشید. یک کلاس در Typescript می‌تواند یک کلاس دیگر را توسعه دهد(ارث بری در دات نت) و چندین اینترفیس را پیاده سازی نماید.
Interface: یک اینترفیس فقط شامل تعاریف است و پیاده سازی در آن انجام نخواهد گرفت. یک اینترفیس می‌تواند چندین اینترفیس دیگر را توسعه دهد.
Function: معادل متد در دات نت است. می‌تواند پارامتر ورودی داشته باشد و در صورت نیاز یک مقدار را برگشت دهد.
Scope: دقیقا تمام مفاهیم مربوط به محدوده فضای نام و کلاس و متد در دات نت در این جا نیز صادق است. 


آماده سازی Visual Studio برای شروع به کار
در ابتدا باید Template مربوطه به TypeScript را نصب کنید تا از طریف VS.Net بتوانیم به راحتی به این زبان کد نویسی کنیم. می‌توانید فایل نصب را از اینجا دانلود کنید. بعد از نصب از قسمت Template‌های موجود گزینه Html Application With TypeScript را انتخاب کنید

یا از قسمت Add  در پروژه‌های وب خود نظیر MVC گزینه TypeScript File را انتخاب نمایید.


در پست بعدی کد نویسی با این زبان را آغاز خواهیم کرد. 

مطالب
آشنایی با FileTable در SQL Server 2012 بخش 2
ستون دیگر stream_id نام دارد که از نوع uniqueidentifier ROWGUIDCOL است. همان‌گونه که در یاد دارید، در FileStream نیز ناگزیر به تعریف چنین ستونی بودیم. بنابراین FileTable استثناء نیست و در این‌جا نیست چنین فیلدی توسط SQL Server تعریف می‌شود. اگر فایل‌ها و پوشه‌ها جابه‌جا نمی‌شدند می‌توانستید از هر دو ستون path_locator یا stream_id برای شناسایی یک رکورد از جدول بهره ببرید. ولی با جابه‌جایی یک فایل و یا به عبارت دیگر تغییر پدر آن در ساختار سلسله‌مراتبی، مقدار path_locator نیز تغییر می‌کند، پس ناگزیر به استفاده از این ستون برای ارجاع به یک ردیف در جدول هستیم.
هر ردیف از جدول نمایان‌گر یک فایل یا پوشه است، بنابراین به ستونی نیاز داریم که بتوانیم این موضوع را نشان دهیم. بر این پایه از ستون is_directory بهره می‌بریم که 1 بودن آن نشان‌دهنده‌ی این است که این ردیف از جدول به یک پوشه ارجاع دارد.
نام فایل یا پوشه در ستونی به نام name نگه‌داری می‌شود که رشته‌ای از نوع (nvarchar(255 است. افزون بر این ستون، ستون‌های دیگری نیز در این جدول وجود دارد که ویژگی‌های یک فایل مانند پنهان‏‌بودن، فقط‏‌خواندنی و ... توسط آن توسط آن به دست می‏آید. ستون پسین file_stream نام دارد که برای پوشه‌ها، محتوای آن Null است. علت آن این است که محتوای واقعی فایل در این ستون نگه‌داری می‌شود. در واقع یک (varbinary(max با ویژگی‌های fileStream است که محتوای باینری آن در سیستم فایل NTFS ذخیره می‌شود. مدیریت پشت صحنه‌ی این ستون برعهده‌ی SQL Server است.
افزون بر این 14 ستون، هر FileTable شامل سه ستون محاسباتی به شرح زیر است:

ستون parent_path_locator نتیجه‏‌ی فراخوانی تابع (GetAncestor(1 در ستون path_locator است که جهت به دست آوردن پوشه‏‌ی پدر یک فایل و پوشه استفاده می‏‌شود. ستون file_type که از مقدار رشته‏‌ای ستون name تجزیه شده است، پسوند فایل را برمی‏‌گرداند. و ستون cached_file_size اندازه‌ی بایت ذخیره‏‌شده ستون file_stream  را برمی‏‌گرداند. با این ساختار ثابت در اینجا، هر FileTable هر آن‏چه از File System نیاز دارید در یک پوشه‏ی اشتراکی به شما می‏‌دهد.

این یعنی نمایش بی‏‌واسطه FileTable به هر کاربر یا برنامه. به طوری که برای نمایش یا به‏‌روزرسانی جدول می‌توانید از روش استاندارد I/O مانند کشیدن و رهاکردن با Windows Explorer یا برنامه‏‌نویسی با  System.IO.FileStream  و API‌های ویندوز استفاده کنید. این‏‌چنین:

- ایجاد یک فایل یا پوشه در سیستم فایل  -> افزودن یک ردیف به جدول

- افزودن یک ردیف به جدول -> ایجاد یک فایل یا پوشه در سیستم فایل 

با کپی فایل‌ها در مسیر بالا، به صورت خودکار رکوردهای زیر در جدول PhotoTable در پایگاه‌داده‌ها افزوده می‌شود: 

به طور خلاصه پیش از این برای افزودن به FileStream دو راه کار پیش رو داشتید. یکی استفاده از T-SQL و دیگر sqlFileStream اکنون SQL Server 2012 راه کار سوم را پیشنهاد می‌کند. استفاده از File System در این روش FileStream  به طور خودکار پر می‌شود. 

پیش از ساخت یک FileTable بیان این نکته دارای اهمیت است که با کپی فایل‏‌ها و پوشه‏‌ها هیچ چیز جدیدی به NTFS افزوده نمی‌شود بلکه محتوای فایل به FileStream افزوده می‌شود و SQL Server با بررسی همزمان FileStream و FileTable نمایشی از ردیف‏‌های FileTable به صورت یک پوشه‏‌ی اشتراکی نشان می‌دهد. این نکته پاسخی به این پرسش خواهد بود که آیا با استفاده از FileTable حجم پایگاه‏‌داده‏‌ها دو برابر خواهد شد و در نتیجه دشواری‏‌ها و چالش‏‌های نگه‏داری و پشتیبانی را پیش رو خواهیم داشت!؟ که پاسخ "خیر" خواهد بود. 

ایجاد یک  FileTable

پیش از این در همین تارنما، روش فعال کردن FileStream در SQL Server  را آموزش دیده اید. اگر درست به خاطر داشته باشید، چیزی شبیه به دستورهای زیر بود:

CREATE DATABASE MyFileArchive
ON PRIMARY
(NAME = MyFileArchive_data,
FILENAME = 'C:\Demo\MyFileArchive_data.mdf'),
FILEGROUP FileStreamGroup CONTAINS FILESTREAM
(NAME = PhotoFileLibrary_blobs,
FILENAME = 'C:\Demo\MyFiles')
LOG ON
(NAME = PhotoFileLibrary_log,
FILENAME = 'C:\Demo\MyFileArchive_log.ldf')

FileTable  به FileStream متکی است؛ بر این پایه پیش از ایجاد یک FileTable باید FileStream را روی پایگاه‌داده‌ها فعال کنیم. این کار با یک تعریف درست توسط بند FILEGROUP…CONTAINS FILESTREAM انجام می‌شود. 

برای ایجاد FileTable تنها کافی است که بند WITH FILESTREAM را به دستور CREATE DATABASE بیفزایید. (یا برای فعال‌کردن FileTable روی یک پایگاه‌داده‌ی ساخته شده بند SET FILESTREAM را در دستور ALTER DATABASE  بنویسید.) در این بند، از DIRECTORY_NAME برای نام‌گذاری یک پوشه برای پایگاه‌داده‌ها استفاده می‌کنیم. این پوشه در یک پوشه ریشه به نام SQL Server instance نمایش داده خواهد شد. بخش دوم بند NON_TRANSACTED_ACCESS=FULL  است که دسترسی غیرتراکنشی را فعال می‌کند.  با این کار برای هر FileTable  در پایگاه داده یک زیرپوشه درون پوشه‌ای که به نام DIRECTORY_NAME  نام‌گذاری شده است؛ ساخته می‌شود. 

با توجه به آنچه گفته شد برای ایجاد یک پایگاه‌داده با امکان ساخت FileTable دستورهای زیر را اجرا کنید: 

CREATE DATABASE MyFileArchive
ON PRIMARY
(NAME = MyFileArchive_data,
FILENAME = 'C:\Demo\MyFileArchive_data.mdf'),
FILEGROUP FileStreamGroup CONTAINS FILESTREAM
(NAME = PhotoFileLibrary_blobs,
FILENAME = 'C:\Demo\MyFiles')
LOG ON
(NAME = PhotoFileLibrary_log,
FILENAME = 'C:\Demo\MyFileArchive_log.ldf')
WITH FILESTREAM
(DIRECTORY_NAME='FilesLibrary',
NON_TRANSACTED_ACCESS=FULL)
اکنون برای ساخت یک FileTable درون این پایگاه‌داده‌ها از دستور زیر استفاده کنید:
USE MyFileArchive
GO
CREATE TABLE PhotoTable AS FileTable
GO
توجه داشته باشید که چون ستون‌های FileTable از پیش تعریف شده است؛ ایجاد آن فقط با نوشتن دستور امکان پذیر است و مانند یک Table عادی از محیط کاربری SQL Server نمی‌توان بهره برد. 
در Object Explorer از گره‏‌ی Tables، گره‏‌ی FileTables را باز کنید و روی جدولی که هم‌‏اکنون ساختیم راست‏‌کلیک کنید. با انتخاب گزینه‏‌ی Explore FileTable Directory پنجره‏‌ی زیر بازمی‏‌شود:

دنباله دارد ...

مطالب
آموزش (jQuery) جی کوئری 2#
در ادامه مطلب قبلی آموزش (jQuery) جی کوئری 1# به ادامه بحث می‌پردازیم.

توابع سودمند
با وجود آنکه انتخاب کردن و ایجاد مجموعه ای از عناصر صفحه یکی از معمول‌ترین و پراستفاده‌ترین کاربردهای تابع ()$ محسوب می‌شود، این تابع توانایی‌های دیگری نیز دارد. یکی از مفید‌ترین آنها استفاده شدن به عنوان فضای نام گروهی برای توابع سودمند می‌باشد. تعداد زیادی تابع سودمند با استفاده از $ به عنوان فضای نام قابل دسترسی می‌باشند که اکثر نیازهای یک صفحه را پاسخگو می‌باشند در این پست برخی از آنها را معرفی می‌کنیم در پست‌های آینده سعی می‌کنیم توابع سودمند بیشتری را شرح دهیم.

فراخوانی و استفاده از این توابع در ابتدا ممکن است کمی عجیب به نطر برسد. به مثال زیر دقت کنید که تابع سودمند () trim را فراخوانی کرده ایم.
$.trim(someString);
 
در صورتی که نوشتن علامت $ برای شما عجیب به نطر می‌رسد می‌توانید شناسه دیگر با نام jQuery به کار ببرید. کد زیر دقیقا مانند بالا عمل می‌کند شاید درک آن راحت‌تر هم باشد.
jQuery.trim(someString);

بدیهی است که از  jQuery یا $ تنها به عنوان فضای نامی که تابع ()trim در آن تعریف شده اند، استفاده شده باشد.

نکته: اگر چه در نوشته‌های آنلاین jQuery، این عناصر به عنوان توابع سودمند در معرفی شده اند اما در حقیقت آنها متدهایی برای تابع ()$ می‌باشند.

عملکرد صفحه آماده (The document ready handler)
هنگامی که از Unobtrusive JavaScriptاستفاده می‌کنیم، رفتار از ساختار جدا می‌شود، بنابراین برای انجام عملیات روی عناصر صفحه باید منتظر بمانیم تا انها ایجاد شوند. برای رسیدن به این هدف، ما نیاز به راهی داریم که تا زمان ایجاد عناصر DOM روی صفحه منتظر بماند قبل از آن عملیات را اجرا کند.
به طور معمول از onload برای نمونه‌های window استفاده می‌شود، که پس از لود شدن کامل صفحه ، دستور‌ها قابل اجرا می‌باشند. بنابراین ساختار کلی آن کدی مانند زیر خواهد بود:
window.onload = function() {
    $("table tr:nth-child(even)").addClass("even");
};

نوشتن کد به صورت بالا سبب می‌شود که کد پس از بارگذاری کامل صفحه اجرا شود. متاسفانه، مرورگرها تا بعد از ساخته شدن عناصر صفحه صبر نمی‌کنند، بلکه پس از ساخت درخت عناصر صفحه منتظر بارگذاری کامل منابع خارجی صفحه مانند تصاویر نیز می‌مانند و سپس آنها را در پنجره مرورگر نمایش می‌دهند. در نتیجه بازدید کننده زمان زیادی منتظر می‌ماند تا رویداد onload تکمیل شود.
حتی بدتر از آن، زمانی است که اگر به طور مثال یکی از تصاویر با مشکل مواجه شود که زمان قابل توجهی صرف بارگذاری آن شود، کاربر باید تمام این مدت را صبر کند تا پس از آن بتواند با این صفحه کار کند. این نکته می‌تواند دلیلی برای استفاده نکردن از Unobtrusive JavaScriptبرای شروع کار باشد.
اما راه بهتری نیز وجود دارد، می‌توانیم تنها زمانی که قسمت ساختار عناصر صفحه ترجمه شده و HTML به درخت عناصر تبدیل می‌شود، صبر کنیم . پس از آن کد مربوط به رفتار‌ها را اجرا کنیم. رسیدن به این روش برای استفاده از Cross-Browser کمی مشکل است، اما به لطف jQuery و قدرت آن، این امر به سادگی امکان پذیر است و دیگر نیازی به منتظر ماندن برای بارگذاری منابع صفحه مانند تصاویر و ویدیوها نمی‌باشد. Syntax زیر نمونه ای از چنین حالتی است:
$(document).ready(function() {
   $("table tr:nth-child(even)").addClass("even");
});

ابتدا صفحه مورد نظر را به تابع ()$ ارسال کرده ایم، سپس هر زمان که آن صفحه آماده شد (Ready) ، تابع ارسال شده به آن اجرا خواهد شد. البته می‌توان کد نوشته شده بالا را به شکل مختصرتری هم نوشت:
$(function() {
    $("table tr:nth-child(even)").addClass("even");
});

با ارسال تابع به ()$، ما مرورگر را مجبور می‌کنیم که برای اجرای کد تا زمانی که DOM کامل لود شود (فقط DOM لود شود) منتظر بماند. حتی بهتر از آن ما می‌توانیم از این تکنیک چندین با در همان سند HTML استفاده کرده و مرورگر تمامی تابع‌های مشخص شده توسط ما را به ترتیب اجرا خواهد کرد. (یعنی من در دیک صفحه می‌توانم چنین بار تابع ()ready را فراخوانی کنم). در مقابل روش OnLoad پنجره فقط اجازه اجرای یکبار تابع را به ما می‌دهد.
این هم یکی دیگر از کارکردهای دیگر تابع ()$ می‌باشد. حال به یکی دیگر از امکاناتی که این تابع برای ما فراهم می‌کند دقت کنید.

ساختن اجزای DOM (ساختن عناصر صفحه)
یکی دیگر از کارهایی که تابع ()$ می تواند برای ما انجام دهد ایجاد کردن عناصر صفحه است. به این منظور ورودی تابع ()$ را یک رشته که حاوی دستور HTML مربوط به ساخت یک عنصر می‌باشد، قرار می‌دهیم. برای مثال دستور زیر یک تگ p ایجاد می‌کند:
$("<p>Hi there!</p>")

اما ایجاد یک عنصر DOM یا (سلسله مراتب عناصر DOM) برای ما به تنهایی سودمند نیست، و هدف ما چیز دیگری است. ایجاد اشیا صفحه توسط ()$ زمانی برای ما مفید خواهد بود که بخواهیم به هنگام ساخت، تابعی بروی آن اعمال کنیم یا به محض ساخت آن را به تابعی ارسال کنیم به کد زیر دقت کنید:
<html>
   <head>
        <title>Follow me!</title>
        <script type="text/javascript" src="../scripts/jquery-1.2.js"></script>
        <script type="text/javascript">
           // در زمان Reday بودن صفحه عنصر مورد نظر ایجاد می‌شود
           $(function(){
              $("<p>Hi there!</p>").insertAfter("#followMe");
           });
        </script>
    </head>
<body>
     <p id="followMe">Follow me!</p>
</body>
</html>

در کد بالا زمانی که صفحه مورد نظر Ready شد تابع مورد نظر ما اجرا شده و در عناصر صفحه بعد از عنصری که id آن followMe می‌باشد یک عنصر p را ایجاد می‌کند. که خروجی آن شبیه تصویر زیر خواهد بود.

مزیت دیگر jQuery این است که در صورتی که امکانی را ندارد شما به آسانی می‌توانید آن را توسعه داده و برای آن پلاگین طراحی کنید.

برای پایان دادن به این پست همانطور که دیدیم jQuery قادر به انجام کارهای زیر است:
  • انتخاب عناصر و ایجاد مجموعه ای از آنها که آماده اعمال متد‌های مختلف می‌باشند.
  • استفاده به عنوان یک فضای نام برای توابع سودمند.
  • ایجاد اشیا مختلف HTML بروی صفحه.
  • اجرای کد به محض آماده شدن اشیای صفحه.

موفق وموید باشید

مطالب
بررسی خطای cycles or multiple cascade paths و یا cyclical reference در EF Code first
ابتدا مثال کامل این قسمت را با شرح زیر درنظر بگیرید؛ در اینجا هر کاربر، یک کارتابل می‌تواند داشته باشد (رابطه یک به صفر یا یک) و تعدادی سند منتسب به او (رابطه یک به چند).  همچنین روابط بین کارتابل و اسناد نیز چند به چند است:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Data.Entity.ModelConfiguration;

namespace EF_General.Models.Ex18
{
    public class UserProfile
    {
        public int UserProfileId { set; get; }
        public string UserName { set; get; }

        [ForeignKey("CartableId")]
        public virtual Cartable Cartable { set; get; } // one-to-zero-or-one
        public int? CartableId { set; get; }

        public virtual ICollection<Doc> Docs { set; get; } // one-to-many
    }

    public class Doc
    {
        public int DocId { set; get; }
        public string Title { set; get; }
        public string Body { set; get; }

        [ForeignKey("UserProfileId")]
        public virtual UserProfile UserProfile { set; get; }
        public int UserProfileId { set; get; }

        public virtual ICollection<Cartable> Cartables { set; get; } // many-to-many
    }

    public class Cartable
    {
        public int CartableId { set; get; }

        [ForeignKey("UserProfileId")]
        public virtual UserProfile UserProfile { set; get; }
        public int UserProfileId { set; get; }

        public virtual ICollection<Doc> Docs { set; get; } // many-to-many
    }

    public class UserProfileMap : EntityTypeConfiguration<UserProfile>
    {
        public UserProfileMap()
        {
            this.HasOptional(x => x.Cartable)
                .WithRequired(x => x.UserProfile)
                .WillCascadeOnDelete();
        }
    }

    public class MyContext : DbContext
    {
        public DbSet<UserProfile> UserProfiles { get; set; }
        public DbSet<Doc> Docs { get; set; }
        public DbSet<Cartable> Cartables { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Configurations.Add(new UserProfileMap());
            base.OnModelCreating(modelBuilder);
        }
    }

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

    public static class Test
    {
        public static void RunTests()
        {
            Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, Configuration>());
            using (var context = new MyContext())
            {
                var user = context.UserProfiles.Find(1);
                if (user != null)
                    Console.WriteLine(user.UserName);
            }
        }
    }
}
اگر این مثال را اجرا کنیم، به خطای ذیل برخواهیم خورد:
Introducing FOREIGN KEY constraint 'FK_DocCartables_Cartables_Cartable_CartableId' 
on table 'DocCartables' may cause cycles or multiple cascade paths. Specify 
ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint. See previous errors.
علت اینجا است که EF به صورت پیش فرض ویژگی cascade delete را برای حالات many-to-many و یا کلیدهای خارجی غیرنال پذیر اعمال می‌کند.
این دو مورد در کلاس‌های Doc و Cartable با هم وجود دارند که در نهایت سبب بروز circular cascade delete (حذف آبشاری حلقوی) می‌شوند و بیشتر مشکل SQL Server است تا EF؛ از این لحاظ که SQL Server در این حالت نمی‌تواند در مورد نحوه حذف خودکار رکوردهای وابسته درست تصمیم‌گیری و عمل کند. برای رفع این مشکل تنها کافی است کلید خارجی تعریف شده در دو کلاس Doc و کارتابل را nullable تعریف کرد تا cascade delete اضافی پیش فرض را لغو کند:
public int? UserProfileId { set; get; }
راه دیگر، استفاده از تنظیمات Fluent و تنظیم WillCascadeOnDelete به false است که به صورت پیش فرض در حالات ذکر شده (روابط چند به چند و یا کلید خارجی غیرنال پذیر)، true است.

شبیه به همین خطا نیز زمانی رخ خواهد داد که در یک کلاس حداقل دو کلید خارجی تعریف شده باشند:
The referential relationship will result in a cyclical reference that is not allowed. [ Constraint name =  ]
در اینجا نیز با نال پذیر تعریف کردن این کلیدهای خارجی، خطای cyclical reference برطرف خواهد شد.