نظرات مطالب
انجام کارهای زمانبندی شده در برنامه‌های ASP.NET توسط DNT Scheduler
نیازی نیست. چون طول عمر کل این ماژول دقیقا معادل طول عمر برنامه‌ی وب است. خاتمه‌ی آن هم به صورت خودکار با از حافظه خارج کردن AppDomain برنامه توسط IIS انجام می‌شود. تا زمانیکه برنامه در حال اجرا است این ماژول هم به همین ترتیب. هر زمان که IIS تصمیم به خاتمه‌ی برنامه گرفت، نه این ماژول، هیچ ماژول دیگری هم فرصت مقاومت پیدا نمی‌کند و راسا به همراه AppDomain جاری خاتمه می‌یابد.
نظرات مطالب
روش‌هایی برای بهبود قابلیت دیباگ بسته‌های NuGet
- کتابخانه‌ای که ذکر کردید، از روش symbol server نیوگت استفاده می‌کند (که در بحث جاری مطرح شده) و نه قرار دادن فایل‌های pdb در بسته‌ی نیوگت. به همین جهت ارتباطی به issue ای که ارسال کردید و در مورد pdbهای embedded هست، ندارد و فایل‌های pdb دریافتی از symbol server، در پوشه‌ی bin کپی نمی‌شوند و در صورت دریافت، سراسری هستند (ذخیره در کش عمومی سیستم و بارگذاری مجدد از همان کش).
- هدف از source link این هست که بتوان قطعه کد کتابخانه‌ی ثالثی را در حین دیباگ مشاهده کرد. هدف از pdb دریافتی از nuget هم این است که اگر در حین کار با کتابخانه‌ای به استثنائی رسیدید، اطلاعات دیباگ بیشتری مانند شماره سطر کدهای مرتبط با آن کتابخانه را نمایش دهد و هر دو مورد هم بدون هیچ تنظیم اضافه‌تری در فایل csproj، با VSCode کار می‌کنند.

یک مثال با VSCode:
فایل launch.json پروژه به این صورت تغییر کرد (بر اساس توضیحات انتهای مطلب):
{
    // Use IntelliSense to find out which attributes exist for C# debugging
    // Use hover for the description of the existing attributes
    // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
    "version": "0.2.0",
    "configurations": [
        {
            "name": ".NET Core Launch (console)",
            "type": "coreclr",
            "request": "launch",
            "preLaunchTask": "build",
            // If you have changed target frameworks, make sure to update the program path.
            "program": "${workspaceFolder}/bin/Debug/netcoreapp3.1/EFCoreDbFunctionsSample.dll",
            "args": [],
            "cwd": "${workspaceFolder}",
            // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
            "console": "internalConsole",
            "stopAtEntry": false,
            "justMyCode": false,
            "symbolOptions": {
                "searchMicrosoftSymbolServer": true
            },
            "suppressJITOptimizations": true,
            "env": {
                "COMPlus_ZapDisable": "1"
            }
        },
        {
            "name": ".NET Core Attach",
            "type": "coreclr",
            "request": "attach",
            "processId": "${command:pickProcess}"
        }
    ]
}
در این زمان با فشردن دکمه‌ی F5 در VSCode، کار دریافت symbols از symbols server شروع می‌شود (و کمی طول می‌کشد و در لاگ پروژه، مراحل آن کاملا مشخص هست). در این حالت فایل‌های pdb را هم داخل پوشه‌ی bin\Debug\netcoreapp3.1 کپی نمی‌کند و در کش سراسری nuget در سیستم قرار می‌دهد تا به ازای هر پروژه، این اطلاعات تکراری حجیم (به ازای هر dll مرتبط با پروژه، یک فایل pdb حجیم از symbol server دریافت خواهد شد)، دریافت نشوند:
Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\3.1.8\System.Private.CoreLib.dll'. Symbols loaded.
Loaded 'D:\Prog\1399\EFCoreDbFunctionsSample\bin\Debug\netcoreapp3.1\EFCoreDbFunctionsSample.dll'. Symbols loaded.
.
.
.
Loaded 'D:\Prog\1399\EFCoreDbFunctionsSample\bin\Debug\netcoreapp3.1\EFCoreSecondLevelCacheInterceptor.dll'. Symbols loaded.
.
.
.
همانطور که مشاهده می‌کنید، Symbols مربوط به کتابخانه‌ی ثالث استفاده شده هم بارگذاری شده‌اند.

در مورد سورس لینک:
قرار دادن یک break-point روی یک سطر:


و سپس زمانیکه در حالت دیباگ (همان فشردن دکمه‌ی F5 در VSCode)، به این سطر رسیدیم، فشردن دکمه‌ی F11، تا سورس متناظر بارگذاری شود:

مسیرراه‌ها
ASP.NET MVC
              نظرات مطالب
              بارگذاری یک یوزرکنترل با استفاده از جی‌کوئری
              سلام آقای نصیری
              امکانش هست در مورد متد stringify و عملی که در اینجا انجام میده کمی توضیح بدهید؟ من اون لینک صفحه JSON رو خوندم ولی متوجه نشدم چرا شما اینجا از این متد استفاده کردید.
              ممنون
              مطالب
              آموزش فایرباگ - #7 - CSS Panel
              پنل CSS مانند پنل جانبیِ Style که در مقاله‌ی قبل بررسی کردیم است با این تفاوت که امکانات بیشتری برای افرادی که قصد تصریف استایل دارند محیا کرده است.
              در این پنل می‌توان به اضافه ، ویرایش و حذف استایل هایی که به صفحه‌ی جاری توسط فایل‌های مختلف اضافه شده اند و یا داخل خود صفحه تعریف شده اند پرداخت.



              همچنین در این پنل امکان ویرایش یک فایل css بصورت کامل وجود دارد ، به این صورت که می‌توانید تمام محتویات فایل مورد نظر را در یک Text area ویرایش کنید.

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


              Options Menu
              با راست کلیک کردن بروی تب CSS و یا کلیک کردن بروی فلش کوچک روی تب CSS قابل دسترس است و امکانات زیر را محیا می‌کند:

              • Expand Shorthand Properties : نمایش دستورات css بصورت کامل ، به این معنی که دستوراتی مانند margin که هم بصورت خلاصه و هم بصورت کامل تعریف می‌شوند را بصورت کامل نمایش می‌دهد. مثلا margin را چهار مقدار margin-top , margin-right , margin-bottom , margin-left نمایش می‌دهد.

              • Color As Hex , Color As RGB , Color As HSL : با انتخاب یکی از سه مقدار ذکر شده ، فرمت نمایش رنگ‌ها به حالت انتخاب شده تغییر می‌کند.
                مثلا دستور color : #000000 به این صورت نمایش داده می‌شود :‭ color : rgb(0, 0, 0) 

              • Refresh : این گزینه محتویات پنل را بروز می‌کند.

              Panel Toolbar
              ابزاری موجود در این پنل مشابه پنل‌های دیگر در بالای پنل و در زیر تب پنل‌ها قرار دارد و شامل ابزارهای زیر می‌شود:

              • Edit Button : این ابزار به دو صورت Live Edit و Source Edit در دسترس هست که با کلیک بروی فلش کوچکی که در سمت راست دکمه قرار دارد می‌توان نوع آن را تغییر داد.
                انتخاب حالت Source Edit ، باعث می‌شود سورس فایل به همان صورتی که به مرورگر ارسال شده نمایش داده شود. ( کامنت‌ها ، فرمت فایل و ... حفظ می‌شود. )
                حالت Live Edit هم باعث نمایش محتویات فایل بصورت مرتب شده می‌شود. ( کامنت‌ها و دستوراتی که توسط مرورگر تفسیر نشده اند نمایش داده نمی‌شوند. )



              • CSS Location Menu : نام فایل جاری که در پنل در حال نمایش است را نمایش می‌دهد و همچنین با کلیک بروی آن ، فایل‌های استایل دیگری که در صفحه بارگزاری شده اند را نمایش می‌دهد. با کلیک بروی هرکدام از فایل‌های نمایش داده شده ، همان فایل در پنل باز می‌شود.

                استایل هایی که در خود صفحه تعریف شده اند با نام خود صفحه در این قسمت نمایش داده می‌شوند و اگر استایل‌های در چندین تگ style تعریف شده باشند ، دومین تگ با #2 ، سومین با #3 و ... مشخص می‌شوند.

                هنگام باز بودن :
                1- فایل هایی که از پوشه‌های مختلف در صفحه بارگذاری شده اند ، با نام پوشه از هم تفکیک شده اند:



                2- با تایپ کردن عبارت دلخواه می‌توان نتایج را محدود کرد:



              Panel
              منظور از پنل ، قسمتی هست که استایل بصورت فرمت شده و نمایش داده شده است.


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

               Editing rules
              برای ویرایش تعاریف CSS شامل Selector‌ها ، دستورات و مقادیر ، این پنل ابزارهای مفیدی ارائه می‌کند.
              برای ویرایش یک selector ، دستور یا مقدار آن بروی آن عبارت کلیک کنید ، در همین حال یک text box ظاهر می‌شود و می‌توانید مقدار جدید را وارد کنید. پس از انجام ویرایش مورد نظر بروی قسمتی از صفحه کلیک کنید یا کلید Tab سپس Esc را بزنید. برای ویرایش دستورات بعدی ، کلید Tab را بزنید و برای لغو تغییر جاری ، کلید Esc را بزنید.

              برای ایجاد یک rule جدید ، بروی قسمتی از پنل راست کلیک کرده و سپس گزینه‌ی "New Rule..." را برگزینید.
              برای ایجاد یک property هم چند راه وجود دارد:

              • بروی قسمت از فضای خالی تعریف یک استایل دوبار کلیک کنید.
              • در قسمتی از تعریف یک استایل راست کلیک کرده و گزینه‌ی "New Property..." را انتخاب کنید.
              • بروی مقدار آخرین property کلیک کرده و کلید Tab را بزنید.


              هنگام ویرایش یا ایجاد یک Rule , Propery یا مقدار بصورت inline ، حاشیه‌ی text box متناسب با مقدار وارد شده رنگی را که نمایانگر حالت ذخیره‌ی مقدار وارد شده است نمایش می‌دهد. برای مثال اگر مقداری که برای یک selector وارد شده است نامعتبر باشد ، رنگ حاشیه‌ی text box قرمز می‌شود.
              جدول زیر حالت‌های مختلف را شرح می‌دهد:

              رنگ حاشیه
              Selectorها
              نام Properyها
              مقادیر Propertyها و Ruleها
               خاکستری تغییری ایجاد نشده استتغییری ایجاد نشده است
              تغییری ایجاد نشده است
               قرمز selector نامعتبر است
              نام نامعتبر است
              مقدار نامعتبر است
               زرد selector صحیح است اما بروی Element فعلی تاثیر ندارد
              نام صحیح است اما مقدار Property غیر مجاز است یا وارد نشده است
               
               سبز selector صحیح است نام و مقدار صحیح هستند
              مقدار صحیح است


              Auto-completion
              زمانی که در حال ایجاد/ویراش کردن یک Rule, Propery یا مقدار آنها هستید ، میتوانید از این قابلیت استفاده کنید. مثلا با وارد کردن # تمام Selector هایی که می‌توانند با # شروع شوند در دسترس شما هستند و با دکمه‌های Up/Down می‌توانید مقادیر ممکن را مرور کنید.
              اگر در حال ویرایش یک مقدار عددی هستید ، می‌توانید با دکمه‌های Up/Down مقادیر را یک واحد یک واحد افزایش دهید. با نگه داشتن کلید Shift و فشردن Up/Down می‌توانید مقادیر را 10تا 10تا تغییر دهید و با نگه داشتن Ctrl بجای Sihft ، یک دهم یک دهم.

              Toggling styles
              با این امکان می‌توانید یک Property را بطور موقت فعال/غیرفعال کنید. با حرکت موس از یک Property یک آیکون قرمز رنگ در کنار آن نمایش داده می‌شود که با کلیک بروی آن ، Property و مقدار آن کمرنگ شده و آیکون قرمز رنگ کنار آن ثابت می‌شود. با کلیک مجدد بروی آن ، Property فعال می‌شود.



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

               گزینهContext
              توضیحات
              Copy Location
              CSS Location Menuآدرس فایل استایل را در حافظه کپی می‌کند.
              Open in New TabCSS Location Menuفایل استایل را در یک تب جدید باز می‌کند.
              Copy Image Location
              image valuesآدرس تصویر را در حافظه کپی می‌کند.
              Open Image in New Tabimage valuesتصویر را در یک تب جدید باز می‌کند.
              Copy Colorcolor valuesمقدار رنگ را در حافظه کپی می‌کند.
              Copy Rule DeclarationCSS selectorSelector و Propertyها را در حافظه کپی می‌کند.
              Copy Style DeclarationCSS selectorفقط Propertyها را در حافظه کپی می‌کند.
              New Rule...
              همه جای پنل
              یک Rule جدید بالای قسمتی که راست کلیک شده ایجاد می‌کند.
              Delete "<selector>"
              CSS selectorRule را حذف می‌کند.
              New Property...
              CSS rule
              یک Property جدید در Ruleی که در آن راست کلیک شده ایجاد می‌کند.
              Edit "<property name>"...
              CSS property
              Property فعلی به حالت ویرایش درمی آید. ( راه ساده‌تر ، کلیک بروی Property است. )
              Delete "<property name>"...CSS propertyProperty فعلی را حذف می‌کند.
              Disable "<property name>"...
              CSS property
              Property فعلی را غیرفعال می‌کند.
              Refreshهمه جای پنل
              محتویات پنل را بروز رسانی می‌کند.
              Inspect in DOM panel
              CSS Location Menu, CSS rule
              فایل استایل یا Rule را در پنل DOM باز می‌کند.


              Elements Side Panel
              در این پنل که سمت راست پنل CSS قرار دارد ، با وارد کردن یک CSS Selector می‌توانید Elementهایی که در صفحه با آن مطابقت دارند را مشاهده کنید.
              برای وارد کردن CSS Selector هم می‌توان مقدار مورد نظر را در قسمت Try a selector... وارد کرد هم می‌توان بروی یکی از Selectorهای پنل راست کلیک کرد و گزینه‌ی Get Matching Elements را برگزید.
              Context Menu این قسمت هم مشابه Context Menu پنل HTML هست و فقط در ورژن 1.11 گزینه‌ی Paste HTML اضافه شده که در این کامنت از مقاله‌ی آموزش فایرباگ - #5 - HTML Panel توضیح داده شده است.

              نظرات مطالب
              پیاده سازی کنترلرهای Angular با استفاده از Typescript
              من از ورژن 1.3.15 angular  استفاده میکنم و در صفحه یک چنین اروری میده Error: [ng:areq] http://errors.angularjs.org/1.3.15/ng/areq?p0=Product.Controller&p1=not%20a%20function%2C%20got%20undefined 
              مثل اینکه نوع تعریف controller در این ورژن متفاوت با قبله.چطور میشه  کد  typescript  رو اصلاح کرد تا مشکل حل بشه؟
              نظرات مطالب
              Implementing second level caching in EF code first
              خیر. از این جهت که کتابخانه فوق در اصل برای کار با کش IIS طراحی شده و زمانیکه absoluteExpiration آن‌را تنظیم می‌کنید، خود IIS به صورت خودکار موارد قدیمی را حذف می‌کند (آیتم‌های موجود در کش مدت دار خواهند شد). به علاوه IIS هر زمان که احساس کند از لحاظ مصرف حافظه زیر فشار است راسا شروع به حذف کردن آیتم‌های موجود در کش می‌کند.
              جهت اطلاع اکثر قسمت‌های سایت جاری از کتابخانه فوق استفاده می‌کنند و تابحال مشکلی با مصرف حافظه مشاهده نشده.
              مطالب
              آشنایی با NHibernate - قسمت ششم

              آشنایی با Automapping در فریم ورک Fluent NHibernate

              اگر قسمت‌های قبل را دنبال کرده باشید، احتمالا به پروسه طولانی ساخت نگاشت‌ها توجه کرده‌اید. با کمک فریم ورک Fluent NHibernate می‌توان پروسه نگاشت domain model خود را به data model متناظر آن به صورت خودکار نیز انجام داد و قسمت عمده‌ای از کار به این صورت حذف خواهد شد. (این مورد یکی از تفاوت‌های مهم NHibernate با نمونه‌های مشابهی است که مایکروسافت تا تاریخ نگارش این مقاله ارائه داده است. برای مثال در نگار‌ش‌های فعلی LINQ to SQL یا Entity framework ، اول دیتابیس مطرح است و بعد ساخت کد از روی آن، در حالیکه در اینجا ابتدا کد و طراحی سیستم مطرح است و بعد نگاشت آن به سیستم داده‌ای و دیتابیس)

              امروز قصد داریم یک سیستم ساده ثبت خبر را از صفر با NHibernate پیاده سازی کنیم و همچنین مروری داشته باشیم بر قسمت‌های قبلی.

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

              ابتدا یک پروژه کنسول جدید را به نام NHSample2 آغاز کنید. سپس ارجاعاتی را به اسمبلی‌های زیر به آن اضافه نمائید:
              FluentNHibernate.dll
              NHibernate.dll
              NHibernate.ByteCode.Castle.dll
              NHibernate.Linq.dll
              و ارجاعی به اسمبلی استاندارد System.Data.Services.dll دات نت فریم ورک سه و نیم

              سپس پوشه‌ای را به نام Domain به این پروژه اضافه نمائید (کلیک راست روی نام پروژه در VS.Net و سپس مراجعه به منوی Add->New folder). در این پوشه تعاریف موجودیت‌های برنامه را قرار خواهیم داد. سه کلاس جدید Category ، User و News را در این پوشه ایجاد نمائید. محتویات این سه کلاس به شرح زیر هستند:

              namespace NHSample2.Domain
              {
              public class User
              {
              public virtual int Id { get; set; }
              public virtual string UserName { get; set; }
              public virtual string Password { get; set; }
              }
              }


              namespace NHSample2.Domain
              {
              public class Category
              {
              public virtual int Id { get; set; }
              public virtual string CategoryName { get; set; }
              }
              }


              using System;

              namespace NHSample2.Domain
              {
              public class News
              {
              public virtual Guid Id { get; set; }
              public virtual string Subject { get; set; }
              public virtual string NewsText { get; set; }
              public virtual DateTime DateEntered { get; set; }
              public virtual Category Category { get; set; }
              public virtual User User { get; set; }
              }
              }
              همانطور که در قسمت‌های قبل نیز ذکر شد، تمام خواص پابلیک کلاس‌های Domain ما به صورت virtual تعریف شده‌اند تا lazy loading را در NHibernate فعال سازیم. در حالت lazy loading ، اطلاعات تنها زمانیکه به آن‌ها نیاز باشد بارگذاری خواهند شد. این مورد در حالتیکه نیاز به نمایش اطلاعات تنها یک شیء وجود داشته باشد بسیار مطلوب می‌باشد، یا هنگام ثبت و به روز رسانی اطلاعات نیز یکی از بهترین روش‌ها است. اما زمانیکه با لیستی از اطلاعات سروکار داشته باشیم باعث کاهش افت کارآیی خواهد شد زیرا برای مثال نمایش آن‌ها سبب خواهد شد که 100 ها کوئری دیگر جهت دریافت اطلاعات هر رکورد در حال نمایش اجرا شود (مفهوم دسترسی به اطلاعات تنها در صورت نیاز به آن‌ها). Lazy loading و eager loading (همانند مثال‌های قبلی) هر دو در NHibernate به سادگی قابل تنظیم هستند (برای مثال LINQ to SQL به صورت پیش فرض همواره lazy load است و تا این تاریخ راه استانداردی برای امکان تغییر و تنظیم این مورد پیش بینی نشده است).

              اکنون کلاس جدید Config را به برنامه اضافه نمائید:

              using FluentNHibernate.Automapping;
              using FluentNHibernate.Cfg;
              using FluentNHibernate.Cfg.Db;
              using NHibernate;
              using NHibernate.Cfg;
              using NHibernate.Tool.hbm2ddl;

              namespace NHSample2
              {
              class Config
              {
              public static Configuration GenerateMapping(IPersistenceConfigurer dbType)
              {
              var cfg = dbType.ConfigureProperties(new Configuration());

              new AutoPersistenceModel()
              .Where(x => x.Namespace.EndsWith("Domain"))
              .AddEntityAssembly(typeof(NHSample2.Domain.News).Assembly).Configure(cfg);

              return cfg;
              }

              public static void GenerateDbScript(Configuration config, string filePath)
              {
              bool script = true;//فقط اسکریپت دیتابیس تولید گردد
              bool export = false;//نیازی نیست بر روی دیتابیس هم اجرا شود
              new SchemaExport(config).SetOutputFile(filePath).Create(script, export);
              }

              public static void BuildDbSchema(Configuration config)
              {
              bool script = false;//آیا خروجی در کنسول هم نمایش داده شود
              bool export = true;//آیا بر روی دیتابیس هم اجرا شود
              bool drop = false;//آیا اطلاعات موجود دراپ شوند
              new SchemaExport(config).Execute(script, export, drop);
              }

              public static void CreateSQL2008DbPlusScript(string connectionString, string filePath)
              {
              Configuration cfg =
              GenerateMapping(
              MsSqlConfiguration
              .MsSql2008
              .ConnectionString(connectionString)
              .ShowSql()
              );
              GenerateDbScript(cfg, filePath);
              BuildDbSchema(cfg);
              }

              public static ISessionFactory CreateSessionFactory(IPersistenceConfigurer dbType)
              {
              return
              Fluently.Configure().Database(dbType)
              .Mappings(m => m.AutoMappings
              .Add(
              new AutoPersistenceModel()
              .Where(x => x.Namespace.EndsWith("Domain"))
              .AddEntityAssembly(typeof(NHSample2.Domain.News).Assembly))
              )
              .BuildSessionFactory();
              }
              }
              }

              در متد GenerateMapping از قابلیت Automapping موجود در فریم ورک Fluent Nhibernate استفاده شده است (بدون نوشتن حتی یک سطر جهت تعریف این نگاشت‌ها). این متد نوع دیتابیس مورد نظر را جهت ساخت تنظیمات خود دریافت می‌کند. سپس با کمک کلاس AutoPersistenceModel این فریم ورک، به صورت خودکار از اسمبلی برنامه نگاشت‌های لازم را به کلاس‌های موجود در پوشه Domain ما اضافه می‌کند (مرسوم است که این پوشه در یک پروژه Class library مجزا تعریف شود که در این برنامه جهت سهولت کار در خود برنامه قرار گرفته است). قسمت Where ذکر شده به این جهت معرفی گردیده است تا Fluent Nhibernate برای تمامی کلاس‌های موجود در اسمبلی جاری، سعی در تعریف نگاشت‌های لازم نکند. این نگاشت‌ها تنها به کلاس‌های موجود در پوشه دومین ما محدود شده‌اند.
              سه متد بعدی آن، جهت ایجاد اسکریپت دیتابیس از روی این نگاشت‌های تعریف شده و سپس اجرای این اسکریپت بر روی دیتابیس جاری معرفی شده، تهیه شده‌اند. برای مثال CreateSQL2008DbPlusScript یک مثال ساده از استفاده دو متد قبلی جهت ایجاد اسکریپت و دیتابیس متناظر اس کیوال سرور 2008 بر اساس نگاشت‌های برنامه است.
              با متد CreateSessionFactory در قسمت‌های قبل آشنا شده‌اید. تنها تفاوت آن در این قسمت، استفاده از کلاس AutoPersistenceModel جهت تولید خودکار نگاشت‌ها است.

              در ادامه دیتابیس متناظر با موجودیت‌های برنامه را ایجاد خواهیم کرد:

              using System;

              namespace NHSample2
              {
              class Program
              {
              static void Main(string[] args)
              {
              Config.CreateSQL2008DbPlusScript(
              "Data Source=(local);Initial Catalog=HelloNHibernate;Integrated Security = true",
              "db.sql");

              Console.WriteLine("Press a key...");
              Console.ReadKey();
              }
              }
              }

              پس از اجرای برنامه، ابتدا فایل اسکریپت دیتابیس به نام db.sql در پوشه اجرایی برنامه تشکیل خواهد شد و سپس این اسکریپت به صورت خودکار بر روی دیتابیس معرفی شده اجرا می‌گردد. دیتابیس دیاگرام حاصل را در شکل زیر می‌توانید ملاحظه نمائید:



              همچنین اسکریپت تولید شده آن، صرفنظر از عبارات drop اولیه، به صورت زیر است:

              create table [Category] (
              Id INT IDENTITY NOT NULL,
              CategoryName NVARCHAR(255) null,
              primary key (Id)
              )

              create table [User] (
              Id INT IDENTITY NOT NULL,
              UserName NVARCHAR(255) null,
              Password NVARCHAR(255) null,
              primary key (Id)
              )

              create table [News] (
              Id UNIQUEIDENTIFIER not null,
              Subject NVARCHAR(255) null,
              NewsText NVARCHAR(255) null,
              DateEntered DATETIME null,
              Category_id INT null,
              User_id INT null,
              primary key (Id)
              )

              alter table [News]
              add constraint FKE660F9E1C9CF79
              foreign key (Category_id)
              references [Category]

              alter table [News]
              add constraint FKE660F95C1A3C92
              foreign key (User_id)

              references [User]

              اکنون یک سری گروه خبری، کاربر و خبر را به دیتابیس خواهیم افزود:

              using System;
              using FluentNHibernate.Cfg.Db;
              using NHibernate;
              using NHSample2.Domain;

              namespace NHSample2
              {
              class Program
              {
              static void Main(string[] args)
              {
              using (ISessionFactory sessionFactory = Config.CreateSessionFactory(
              MsSqlConfiguration
              .MsSql2008
              .ConnectionString("Data Source=(local);Initial Catalog=HelloNHibernate;Integrated Security = true")
              .ShowSql()
              ))
              {
              using (ISession session = sessionFactory.OpenSession())
              {
              using (ITransaction transaction = session.BeginTransaction())
              {
              //با توجه به کلیدهای خارجی تعریف شده ابتدا باید گروه‌ها را اضافه کرد
              Category ca = new Category() { CategoryName = "Sport" };
              session.Save(ca);
              Category ca2 = new Category() { CategoryName = "IT" };
              session.Save(ca2);
              Category ca3 = new Category() { CategoryName = "Business" };
              session.Save(ca3);

              //سپس یک کاربر را به دیتابیس اضافه می‌کنیم
              User u = new User() { Password = "123$5@1", UserName = "VahidNasiri" };
              session.Save(u);

              //اکنون می‌توان یک خبر جدید را ثبت کرد

              News news = new News()
              {
              Category = ca,
              User = u,
              DateEntered = DateTime.Now,
              Id = Guid.NewGuid(),
              NewsText = "متن خبر جدید",
              Subject = "عنوانی دلخواه"
              };
              session.Save(news);

              transaction.Commit(); //پایان تراکنش
              }
              }
              }

              Console.WriteLine("Press a key...");
              Console.ReadKey();
              }
              }
              }
              جهت بررسی انجام عملیات ثبت هم می‌توان به دیتابیس مراجعه کرد، برای مثال:



              و یا می‌توان از LINQ استفاده کرد:
              برای مثال کاربر VahidNasiri تعریف شده را یافته، اطلاعات آن‌را نمایش دهید؛ سپس نام او را به Vahid ویرایش کرده و دیتابیس را به روز کنید.

              برای اینکه کوئری‌های LINQ ما شبیه به LINQ to SQL شوند، کلاس NewsContext را به صورت ذیل تشکیل می‌دهیم. این کلاس از کلاس پایه NHibernateContext مشتق شده و سپس به ازای تمام موجودیت‌های برنامه، یک متد از نوع IOrderedQueryable را تشکیل خواهیم داد.

              using System.Linq;
              using NHibernate;
              using NHibernate.Linq;
              using NHSample2.Domain;

              namespace NHSample2
              {
              class NewsContext : NHibernateContext
              {
              public NewsContext(ISession session)
              : base(session)
              { }

              public IOrderedQueryable<News> News
              {
              get { return Session.Linq<News>(); }
              }

              public IOrderedQueryable<Category> Categories
              {
              get { return Session.Linq<Category>(); }
              }

              public IOrderedQueryable<User> Users
              {
              get { return Session.Linq<User>(); }
              }
              }
              }
              اکنون جهت یافتن کاربر و به روز رسانی اطلاعات او در دیتابیس خواهیم داشت:

              using System;
              using FluentNHibernate.Cfg.Db;
              using NHibernate;
              using System.Linq;
              using NHSample2.Domain;

              namespace NHSample2
              {
              class Program
              {
              static void Main(string[] args)
              {
              using (ISessionFactory sessionFactory = Config.CreateSessionFactory(
              MsSqlConfiguration
              .MsSql2008
              .ConnectionString("Data Source=(local);Initial Catalog=HelloNHibernate;Integrated Security = true")
              .ShowSql()
              ))
              {
              using (ISession session = sessionFactory.OpenSession())
              {
              using (ITransaction transaction = session.BeginTransaction())
              {
              using (NewsContext db = new NewsContext(session))
              {
              var query = from x in db.Users
              where x.UserName == "VahidNasiri"
              select x;

              //اگر چیزی یافت شد
              if (query.Any())
              {
              User vahid = query.First();
              //نمایش اطلاعات کاربر
              Console.WriteLine("Id: {0}, UserName: {0}", vahid.Id, vahid.UserName);
              //به روز رسانی نام کاربر
              vahid.UserName = "Vahid";
              session.Update(vahid);

              transaction.Commit(); //پایان تراکنش
              }
              }
              }
              }
              }

              Console.WriteLine("Press a key...");
              Console.ReadKey();
              }
              }
              }
              مباحث تکمیلی AutoMapping

              اگر به اسکریپت دیتابیس تولید شده دقت کرده باشید، عملیات AutoMapping یک سری پیش فرض‌هایی را اعمال کرده است. برای مثال فیلد Id را از نوع identity و به صورت کلید تعریف کرده، یا رشته‌ها را به صورت nvarchar با طول 255 ایجاد نموده است. امکان سفارشی سازی این موارد نیز وجود دارد.

              مثال:

              using FluentNHibernate.Conventions.Helpers;

              public static Configuration GenerateMapping(IPersistenceConfigurer dbType)
              {
              var cfg = dbType.ConfigureProperties(new Configuration());

              new AutoPersistenceModel()
              .Conventions.Add()
              .Where(x => x.Namespace.EndsWith("Domain"))
              .Conventions.Add(
              PrimaryKey.Name.Is(x => "ID"),
              DefaultLazy.Always(),
              ForeignKey.EndsWith("ID"),
              Table.Is(t => "tbl" + t.EntityType.Name)
              )
              .AddEntityAssembly(typeof(NHSample2.Domain.News).Assembly)
              .Configure(cfg);

              return cfg;
              }

              تابع GenerateMapping معرفی شده را اینجا با قسمت Conventions.Add تکمیل کرده‌ایم. به این صورت دقیقا مشخص شده است که فیلدهایی با نام ID باید primary key در نظر گرفته شوند، همواره lazy loading صورت گیرد و نام کلید خارجی به ID ختم شود. همچنین نام جداول با tbl شروع گردد.
              روش دیگری نیز برای معرفی این قرار دادها و پیش فرض‌ها وجود دارد. فرض کنید می‌خواهیم طول رشته پیش فرض را از 255 به 500 تغییر دهیم. برای اینکار باید اینترفیس IPropertyConvention را پیاده سازی کرد:

              using FluentNHibernate.Conventions;
              using FluentNHibernate.Conventions.Instances;

              namespace NHSample2.Conventions
              {
              class MyStringLengthConvention : IPropertyConvention
              {
              public void Apply(IPropertyInstance instance)
              {
              instance.Length(500);
              }
              }
              }
              سپس نحوه‌ی معرفی آن به صورت زیر خواهد بود:

              public static Configuration GenerateMapping(IPersistenceConfigurer dbType)
              {
              var cfg = dbType.ConfigureProperties(new Configuration());

              new AutoPersistenceModel()
              .Conventions.Add()
              .Where(x => x.Namespace.EndsWith("Domain"))
              .Conventions.Add<MyStringLengthConvention>()
              .AddEntityAssembly(typeof(NHSample2.Domain.News).Assembly)
              .Configure(cfg);

              return cfg;
              }

              نکته:
              اگر برای یافتن اطلاعات بیشتر در این مورد در وب جستجو کنید، اکثر مثال‌هایی را که مشاهده خواهید کرد بر اساس نگارش بتای fluent NHibernate هستند و هیچکدام با نگارش نهایی این فریم ورک کار نمی‌کنند. در نگارش رسمی نهایی ارائه شده، تغییرات بسیاری صورت گرفته که آن‌ها را در این آدرس می‌توان مشاهده کرد.

              دریافت سورس برنامه قسمت ششم


              ادامه دارد ...

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

              این مورد، روش پیشنهادی در Angular Seed است و بدین صورت است که تعاریف ماژول‌ها در فایل app.js انجام می‌گیرد. تعاریف و پیاده سازی تمام کنترلر‌ها در فایل controller.js است. و همچنین دایرکتیوها و فیلترها و سرویس‌ها هر کدام در فایل‌ها جداگانه تعریف و پیاده سازی می‌شوند. این روش راه حلی سریع برای پروژه‌های کوچک با تعداد developer‌های کم است. برای مثال زمانی که یک developer در حال ویرایش فایل controller.js است، از آن جا که فایل مورد نظر checkout خواهد شد در نتیجه سایر developer‌ها امکان تغییر در فایل مورد نظر را نخواهند داشت. سورس فایل‌ها به مرور زیاد خواهد شد و در نتیجه debug آن سخت می‌شود. 

              روش دوم

              در این حالت تعاریف کنترلر ها، مدل‌ها و سرویس‌ها هرکدام در یک دایرکتوری مجزا قرار خواهد گرفت. برای هر view یک کنترلر و بنا بر نیاز مدل تعریف می‌کنیم. ساختار آن به صورت زیر می‌شود:

              دایرکتیو‌ها و فیلتر‌ها عموما در یک فایل قرار داده خواهند شد تا بنابر نیاز در جای مناسب رفرنس داده شوند. این روش ساختار مناسب‌تری نسبه به روش قبلی دارد اما دارای معایبی هم چون موارد زیر است:
              »وابستگی بین فایل‌ها مشخص نیست در نتیجه بدون استفاده از کتابخانه هایی نظیر requireJs  با مشکل مواجه خواهید شد.
              »refactoring کد‌ها تا حدودی سخت است.

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

              همان طور که ملاحظه می‌کنید سرویس ها، کنترلر‌ها و حتی مدل‌های مربوط به هر بخش در یک مسیر جداگانه قرار می‌گیرند. علاوه بر آن فایل هایی که قابلیت اشتراکی دارند در مسیری به نام common وجود دارند تا بتوان در جای مناسب برای استفاده از آن‌ها رفرنس داده شود. حتی اگر در پروژه خود فقط یک ماژول دارید باز سعی کنید از این روش برای مدیریت فایل‌های خود استفاده نمایید. اگر با ngStart آشنایی داشته باشید به احتمال زیاد با این روش بیگانه نیستید.
              بررسی چند نکته درباره کد‌های مشترک
              در اکثر پروژه‌های بزرگ، فایل‌ها و کد هایی وجود خواهد داشت که حالت اشتراکی بین ماژول‌ها دارند. در این روش این فایل‌ها در مسیری به نام common یا shared ذخیره می‌شوند. علاوه بر آن در Angular تکنیک هایی برای به اشتراک گذاشتن این اطلاعات وجود دارد.
              »اگر ماژول‌ها وابستگی شدیدی به فایل‌ها و سورس‌های مشترک دارند باید اطمینان حاصل نمایید که این ماژولها فقط به اطلاعات مورد نیاز دسترسی دارند. این اصل interface segregation principle اصول SOLID است.
              »توابعی که کاربرد زیادی دارند و اصطلاحا به عنوان Utility شناخته می‌شوند باید به rootScope$ اضافه شوند تا scope‌های وابسته نیز به آن‌ها دسترسی داشته باشند. این مورد به ویژه باعث کاهش تکرار وابستگی‌های مربوط به هر کنترلر می‌شود.
              »برای جداسازی وابستگی‌های بین دو component بهتر از event‌ها استفاده نمایید. AngularJs این امکان را با استفاده از سرویس‌های on$ و emit$ و broadcast$ به راحتی میسر کرده است.
              نظرات مطالب
              فرم‌های مبتنی بر قالب‌ها در Angular - قسمت چهارم - اعتبارسنجی ورودی‌ها
              ممنون از پیشنهادتون. علاوه بر این میتوان اعتبار سنجی برای اطلاعات فارسی رو هم پیاده سازی کرد. از جمله اعتبار سنجی کد ملی، شناسه ثبت شرکت، شماره‌های تلفن و ...
              از دوستان تقاضا دارم برای داشتن یک ماژول کامل اعتبار سنجی در زمینه اطلاعات فارسی و همچنین اعتبار سنجی‌های کاربردی پیشنهاداتشون رو در این لینک  و یا در همین صفحه مطرح کنند تا در اولین فرصت پیاده سازی و تکمیل شوند.