نظرات مطالب
EF Code First #1
- رشته اتصالی به SQL Server حالت‌های مختلفی می‌تواند داشته باشد. اطلاعات بیشتر
Data Source آن معمولا نام کامپیوتر جاری است یا IP Server. چون در تصویر شما instance name خالی است، از همان وهله‌ی پیش فرض استفاده می‌شود. اگر مقدار داشت می‌شد computer_name/instance_name
Initial Catalog نام بانک اطلاعاتی مدنظر است که قرار است به آن متصل شوید (یا در اینجا به صورت خودکار ساخته شود).
Integrated Security = true به معنای استفاده از اعتبارسنجی ویندوزی است برای اتصال به SQL Server. یعنی کاربر جاری لاگین کرده به سیستم باید دسترسی لازم را برای کار با SQL Server داشته باشد.
- برای فراگیری یک فناوری جدید از برنامه‌های کنسول استفاده کنید و نه ASP.NET. این مباحث عمومی است بین فناوری‌های مختلف استفاده کننده از آن. در یک برنامه‌ی کنسول آغاز کار از متد Main است؛ در یک برنامه‌ی وب از متد Application_Start فایل global.asax.cs خواهد بود.
پاسخ به بازخورد‌های پروژه‌ها
خطای null
مثال یاد شده را بررسی کردم مشکلی نبود. فقط این مثال یک سری وابستگی دارد که باید بررسی کنید آیا موجود هستند یا نه:
- مثلا آیا پوشه و فایل data\AcroFormSample.pdf در کنار فایل exe برنامه شما موجود است؟
- آیا پوشه و تصویر Images\01.png در مسیر فایل اجرایی برنامه واقع شد‌ه‌اند؟
- فونت‌های tahoma.ttf و verdana.ttf آیا در پوشه‌ی fonts سیستم شما موجودند؟
این پوشه‌ها و فایل‌های جانبی، در مجموعه سورس‌های پروژه موجود هستند (در پوشه bin آن).
مطالب
الگوریتم های داده کاوی در SQL Server Data Tools (SSDT) - قسمت اول (مقدمه)
پیشتر مطالبی در رابطه با مفاهیم مخزن داده و داده کاوی در سایت آمده است: ^ و ^ و ^.

در این سری مقالات به معرفی الگوریتم‌های داده کاوی مایکروسافت و نحوه کار کردن با آن‌ها در محیط SQL Server Data Tools (SSDT)  می‌پردازیم. بیشتر متن مقاله ترجمه آزاد از کتاب معروف  Data Mining with Microsoft SQL Server 2008 می باشد که یکی از بهترین کتاب‌ها در زمینه داده کاوی است. از آنجائیکه دسته بندی الگوریتم‌های داده کاوی در SQL Server 2016 نسبت به SQL Server 2008 قدری متفاوت می‌باشد و کتاب فوق به دلیل ورژن SQL قدیمی‌تر، این موضوع را درنظر نگرفته است، بنابراین تغییرات ورژن جدید دسته بندی الگوریتم‌ها نیز لحاظ شده است. جهت درک بهتر مطالب، سعی شده‌است مثال و توضیحاتی براساس تجربه کاری  آورده شود.
برای دریافت SSDT می‌توانید به اینجا مراجعه نمایید.
پس از دریافت و نصب SSDT می‌توان به Visual Studio مراجعه نمود و یک پروژه Analysis Services Multidimensional and Data Mining یا به اختصار  SSAS-M را به شکل زیر ایجاد کرد.

 پس از ایجاد یک پروژه SSAS-M می‌توان در بخش Mining Structure یک ساختار داده کاوی را به شکل زیر ایجاد نمود.

حال بایستی توسط ویزارد، ساختار داده کاوی مورد نظر را ایجاد نمود. در صفحه اول ویزارد، مخزن داده را مشخص می‌نماییم.

در صفحه بعد الگوریتم موردنظر را انتخاب می‌نماییم.

بدیهی است که پس از ساخت ساختار داده کاوی می‌توان الگوریتم‌های دیگری را نیز برای مدل کردن مخزن داده به کار برد.

در این مقاله فرض شده است که خواننده نحوه ساخت  Cube  و  Dimension  را در یک پروژه SSAS-M توسط SSDT ، می‌داند. در صورتیکه به داده کاوی و هوش تجاری علاقمند هستید و به مقدمات بیشتری در رابطه با مطالب فوق نیاز دارید، پیشنهاد می‌شود که فصل‌های یک، سه و چهار کتاب فوق را جهت آشنایی بیشتر مطالعه نمایید.

همانطور که در شکل آخر نیز نشان داده شده است SSDT دارای الگوریتم‌های زیر است:

  • Microsoft_Naive_Bayes
  • Microsoft_Decision_Trees
  • Microsoft_Linear_Regression
  • Microsoft_Clustering
  • Microsoft_ Association_Rules
  • Microsoft_Neural_Network
  • Microsoft_Logistic_Regression
هدف این سری مقالات که به امید خدا در آینده منتشر خواهد شد، آشنایی با الگوریتم‌های داده کاوی فوق و نحوه مدل کردن مخزن داده توسط این الگوریتم‌ها و در نهایت چگونگی تفسیر مدل های داده کاوی تولید شده، می‌باشد.
مطالب
تاریخچه‌ی نگارش‌های مختلف دات نت فریم ورک

حدود 8 سال از ارائه اولین نگارش دات نت فریم ورک می‌گذرد و در ادامه مرور سریعی خواهیم داشت بر عناوین کتابخانه‌های اضافه شده به این مجموعه:



دات نت فریم ورک 1.0
اولین ارائه عمومی آزمایشی آن در PDC 2000 صورت گرفت و در اوایل 2002 به عموم عرضه شد (2/13/2002).
عبارت کد مدیریت شده را به دنیا معرفی کرد (managed code) و شامل اجزای زیر بود:
• GC, JIT
• C#
• Coherent Framework
• XSP….ASP+…ASP.NET!
• WinForms

دات نت فریم ورک 1.1
در اوایل 2003 به همراه ویندوز سرور 2003 و VS 2003 ارائه شد.
• Mobile ASP.NET controls
• Built-in support for ODBC and Oracle databases.
• IPv6 support.

دات نت فریم ورک 2
در اواخر 2005 ارائه شد (11/07/2005) و شامل تازه‌های زیر بود:
• ASP.NET for the Masses
○ Application Building Blocks
§ Parts, Authentication, Role Management, etc
○ Visual Web Developer
• Client Development
• ClickOnce!

دات نت فریم ورک 3
در اواخر 2006 ارائه شد (11/06/2006) و موارد زیر را به این فریم ورک افزود:

• Windows CardSpace - Digital identity interface.
• Windows Presentation Foundation : WPF
○ Vector Graphics, Media and UI
○ Enters the age of UX
• Windows Communication Foundation : WCF
○ Unified messaging model
• Windows Workflow Foundation : WF
○ Coordinating work with durable applications

دات نت فریم ورک 3.5
در پایان 2007 ارائه شد (11/19/2007) و تازه‌های زیر را به همراه داشت:
• Linq
• Expression Trees and Lamda Methods
• Extension Methods
• Paging Support for ADO.NET
• Managed Wrappers for WMI and AD
• Enhancements to WCF and WF
• System.CodeDom namespace
• ASP.NET AJAX
• WCF/WF
○ REST Services
○ Workflow Services
• Client
○ Sync
○ Client app services

در همین زمان نیز دات نت فریم ورک سورس باز شد.

سرویس پک یک دات نت فریم ورک 3.5
در اواسط 2008 ارائه شد (8/11/2008) و به همراه تغییرات زیر بود:
• ASP.NET Dynamic Data
• ADO.NET
○ Entity Framework
○ Data Services (Astoria)
• WCF
○ AtomPub ServiceDocuments
• Client
○ Client Profile
○ Performance
§ Working set and startup time
• Silverlight 2
○ RTM end of 2008
○ Brings power of .NET to the web client
○ Media and RIA .NET platform


دات نت فریم ورک 4.0
نگارش بتای آن در دسترس است و احتمالا نگارش نهایی آن در سال آینده‌ی میلادی به همراه VS2010 ارائه می‌شود. این مجموعه تازه‌های زیر را به همراه خواهد داشت:

• Base Class Library Improvements
○ Managed Extensibility Framework
○ More Core Data Structures
○ I/O Improvements
• Parallel Computing
○ Task Parallel Library
○ Parallel Linq (PLINQ)
○ Coordination Data Structures (CDS)
• Client
○ WPF
§ Client Profile
§ Business Focused Controls
§ Win7 Advances (Multi-touch, etc)
○ ADO.NET
§ Entity Framework v2
□ Code-First Development
□ TDD Support
□ Foreign-Key Support
○ ASP.NET
§ ASP.NET Dynamic Data Improvements
§ ASP.NET MVC
§ ASP.NET Dynamic Data for MVC
§ Extensible Caching Framework
○ WF & WCF
§ Fully Declarative Services
§ Workflow Enhancements
□ New flowchart modeling
□ Workflow Rules Integration
□ … much more…
§ WCF Enhancements
□ Durable Duplex
□ WS-Discovery & UDP Channel
□ In-Process Channel
§ RIA (Silverlight)
□ Simplified N-tier development
□ Business-focused framework

نظرات مطالب
روش نصب اندروید 10 بر روی گوشی‌های قدیمی سامسونگ
روش اصلاح daylight saving time در سیستم عامل اندروید


باتوجه به اینکه از امسال دیگر تغییر ساعت بهاری و تابستانی را نداریم، از ابتدای سال، سیستم عامل‌های اندرویدی، یک ساعت جلوتر را نمایش می‌دهند که در ابتدا تصور بر این بود که مشکل از اپراتورهاست، اما اینطور نیست! ساعت ارسالی توسط آن‌ها صحیح است. مشکل از قدیمی بودن بانک اطلاعاتی tzdata سیستم عامل‌های اندرویدی است.

نگارش جدید و کامپایل شده‌ی این فایل‌ها را از اینجا می‌توانید دریافت کنید: tzdata-new.zip

محل ذخیره شدن بانک اطلاعاتی time-zones در اندروید

بسته به نگارش اندروید شما، یکی از مکان‌های زیر، محل ذخیره سازی دو فایل tzdata و tz_version است:
/data/misc/zoneinfo/tzdata
/system/usr/share/zoneinfo
/apex/com.android.tzdata/etc/tz/tzdata
برای مثال بر روی اندروید 10 من (که روش نصب آن در این مطلب آمده)، مسیر آخری، مسیر اصلی و تاثیرگذار است.


مشکل! به روز رسانی مسیرهای سیستمی اندروید، نیاز به دسترسی root دارند!

تا اینجا مشخص شد که برای رفع مشکل time-zone و به روز رسانی اطلاعات آن، باید دو فایل tzdata و tz_version را در مسیرهای یاد شده، بازنویسی کنیم؛ اما ... اندروید چنین اجازه‌ای را نمی‌دهد!
در سیستم عامل LineageOS 17.1 ای که من نصب کردم، می‌توان با نصب برنامه‌ی معروف Magisk، دسترسی روت پیدا کرد. روش نصب آن هم به صورت زیر است:
1) فایل apk آن‌را از این آدرس دریافت کرده و پسوند آن‌را به zip. تغییر دهید.
2) سیستم را ری‌استارت کرده و رفتن به گزینه‌ی recovery را انتخاب کنید تا پس از ری‌استارت سیستم، وارد برنامه‌ی TWRP شویم (که روش نصب آن در مطلب جاری بحث شده).
3) در برنامه‌ی TWRP، گزینه‌ی install را انتخاب و سپس فایل zip. برنامه‌ی magisk را انتخاب و نصب کنید.
4) پس از نصب، یکبار هم کش را پاک کنید (Wipe cache/dalvik).
5) در آخر بر روی دکمه‌ی Reboot System تا ... وارد اندروید شوید.
 6) پس از راه اندازی سیستم، برنامه‌ی Magisk را اجرا کنید تا مرحله‌ی آخر نصب آن به پایان برسد (یکسری از فایل‌ها را نیاز دارد تا از اینترنت دریافت و نصب کند؛ این نصب، از github و به صورت خودکار است).

پس از نصب magisk، برنامه‌ی total commander را هم نصب کنید. به محض اجرای آن، پیام درخواست دسترسی root آن هم ظاهر می‌شود (این برنامه‌ی magisk هست که این درخواست را تشخیص داده و مدیریت می‌کند) و نیاز است این دسترسی را بدهید تا بتوان:
 1) به مسیر file system root و سپس apex/com.android.tzdata/etc/tz/tzdata وارد شد و دو فایل موجود و قدیمی tzdata و tz_version را به نحو متداولی پاک کرد.
 2) سپس دو فایل جدید tzdata و tz_version را (که لینک دریافت آن کمی بالاتر ارائه شد) به سیستم خود منتقل کنید (همانند تمام فایل‌های دیگر از طریق usb) و در آخر با استفاده از total commander ای که اکنون دسترسی root هم دارد، این فایل‌ها را به مسیر یاد شده، کپی کنید.
 3) اکنون سیستم را ری‌استارت کنید تا تنظیمات جدید خوانده شوند (همانند تصویر زیر، که در آن منطقه زمانی جدید 3:30+ قابل مشاهده‌است):

یک نکته: « Magisk-Modules-Repo / Systemless_TZData » در صورت به روز شدن، این کار نصب دستی tzdata را به صورت خودکار انجام می‌دهد که در زمان نگارش این مطلب، هنوز به‌روز نشده.

مطالب
شروع به کار با EF Core 1.0 - قسمت 5 - استراتژهای تعیین کلید اصلی جداول و ایندکس‌ها
پس از بررسی نحوه‌ی انجام تنظیمات اولیه‌ی کار با EF Core و همچنین آشنایی با مهاجرت‌های آن، مرحله‌ی بعد، مرحله‌ی مدلسازی داده‌ها است و اولین مرحله‌ی آن، نحوه‌ی تعیین کلید اصلی جداول است که در این زمینه، EF Core پیشرفت‌هایی قابل ملاحظه‌ای را نسبت به EF 6.x داشته‌است. در EF 6.x تنها دو حالت کلیدهای اصلی خود افزاینده که توسط بانک اطلاعاتی مدیریت می‌شوند و یا تولید کلید اصلی در سمت کلاینت و توسط برنامه، پشتیبانی می‌شوند. در EF Core، مواردی مانند Sequence و Alternate keys نیز اضافه شده‌اند.


پیش فرض‌های تعیین کلید اصلی در EF Core

به صورت پیش فرض هر خاصیتی که به نام Id و یا type name>Id> باشد، به عنوان primary key تفسیر خواهد شد؛ مانند:
public class Car
{
    public string Id { get; set; }
و یا
public class Car
{
   public string CarId { get; set; }
در مثال اول، نام خاصیت، Id است و در مثال دوم، جمع نام کلاس به همراه Id ذکر شده‌است. یک چنین مواردی، نیازی به تنظیم اضافه‌تری ندارند.


نحوه‌ی تعیین کلید اصلی به صورت صریح

اگر یکی از دو حالت فوق برقرار نباشند، باید کلید اصلی را به نحو صریحی مشخص کرد.
الف) از طریق ویژگی‌ها
public class Car
{
   [Key]
   public string LicensePlate { get; set; }
در اینجا چون LicensePlate نه Id نام دارد و نه جمع نام کلاس به همراه Id است، باید به نحو صریحی توسط ویژگی Key مشخص شود.
ب) با استفاده از روش Fluent API
public class MyContext : DbContext
{
    public DbSet<Car> Cars { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
         modelBuilder.Entity<Car>()
                 .HasKey(c => c.LicensePlate);
    }
 }
روش تنظیم کلید اصلی به صورت صریح، از طریق کدنویسی است که به آن Fluent API یا API روان هم گفته می‌شود. برای اینکار باید متد OnModelCreating کلاس Context برنامه را بازنویسی کرد و سپس از طریق متد HasKey، نام خاصیت کلید اصلی را ذکر نمود.


پیشنیاز کار با ویژگی‌ها در EF Core

در اسمبلی که مدل‌های موجودیت‌ها شما قرار دارند، نیاز است وابستگی System.ComponentModel.Annotations به فایل project.json پروژه اضافه شود، تا ویژگی‌هایی مانند Key، شناسایی و قابل استفاده شوند:
{
   "dependencies": {
          "System.ComponentModel.Annotations": "4.1.0"
   }
}


تعیین کلید ترکیبی و یا Composite key

اگر نیاز است چندین خاصیت را به صورت کلید اصلی معرفی کرد که به آن composite key هم می‌گویند، تنها روش ممکن، استفاده از Fluent API و به صورت زیر است:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
   modelBuilder.Entity<Car>()
                       .HasKey(c => new { c.State, c.LicensePlate });
}
در قسمت HasKey می‌توان چندین خاصیت را نیز جهت تعیین کلید ترکیبی مشخص کرد.


روش‌های مختلف تولید خودکار مقادیر خواص

حالت پیش فرض تولید مقدار فیلدهای Id عددی، همان حالت خود افزاینده‌ای است که توسط بانک اطلاعاتی کنترل می‌شود و یا کلید اصلی که از نوع Guid تعیین شود نیز به صورت خودکار توسط بانک اطلاعاتی در حین عملیات Add، مقدار دهی می‌شود (با استفاده از الگوریتم Guid سری در SQL Server).
 اگر این حالات مطلوب شما نیست، حالت‌های سه گانه‌ی ذیل را می‌توان استفاده کرد:

الف) هیچ داده‌ی خودکاری تولید نشود
برای اینکار می‌توان با استفاده از ویژگی DatabaseGenerated و تنظیم مقدار آن به None، جلوی تولید خودکار کلید اصلی را گرفت. در این حالت باید هم در حین عملیات Add و هم در حین عملیات Update، مقادیر را خودتان مقدار دهی کنید:
public class Blog
{
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int BlogId { get; set; }

    public string Url { get; set; }
}
و یا معادل این تنظیم با استفاده از Fluent API به صورت ذیل است:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
           .Property(b => b.BlogId)
           .ValueGeneratedNever();
}

ب) تولید داده‌های خودکار فقط در حالت Add
حالت Add به این معنا است که داده‌های خواص مشخصی، برای موجودیت‌های «جدید»، به صورت خودکار تولید خواهند شد. اینکه آیا واقعا این مقادیر به صورت خودکار تولید می‌شوند یا خیر، صرفا وابسته‌است به بانک اطلاعاتی در حال استفاده. برای مثال SQL Server برای نوع‌های Guid، به صورت خودکار با کمک الگوریتم SQL Server sequential GUID، کار مقدار دهی یک چنین فیلدهایی را انجام می‌دهد.
این فیلدها باید توسط ویژگی DatabaseGenerated و با مقدار Identity مشخص شوند. در اینجا Identity به معنای فیلدهایی است که به صورت خودکار توسط بانک اطلاعاتی مقدار دهی می‌شوند و الزاما به کلید اصلی اشاره نمی‌کنند. برای مثال در موجودیت ذیل، خاصیت تاریخ ثبت رکورد، از نوع Identity مشخص شده‌است. به این معنا که در حین ثبت اولیه‌ی رکورد آن، نیازی نیست تا خاصیت Inserted را مقدار دهی کرد. اما اینکه آیا SQL Server یک چنین کاری را به صورت خودکار انجام می‌دهد، پاسخ آن خیر است. SQL server فقط برای فیلدهای عددی و Guid ایی که با DatabaseGeneratedOption.Identity مزین شده باشند، مقادیر متناظری را به صورت خودکار تولید می‌کند. برای حالت DateTime نیاز است، مقدار پیش فرض فیلد را صریحا مشخص کرد که توسط ویژگی‌ها میسر نیست و فقط fluent API از آن پشتیبانی می‌کند.
public class Blog
{
   public int BlogId { get; set; }
   public string Url { get; set; }

   [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
   public DateTime Inserted { get; set; }
}
و یا معادل این تنظیم با استفاده از Fluent API به صورت ذیل است:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
           .Property(b => b.Inserted)
           .ValueGeneratedOnAdd();
}
برای تعیین مقدار پیش فرض خاصیت Inserted به نحوی که توسط SQL Server به صورت خودکار مقدار دهی شود، می‌توان از متد HasDefaultValueSql به نحو ذیل استفاده کرد:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .Property(b => b.Inserted)
        .HasDefaultValueSql("getdate()");
}
البته باید درنظر داشت که اگر خاصیت DateTime تعریف شده در اینجا به همین نحو بکاربرده شود، اگر مقداری برای آن در حین تعریف یک وهله جدید از کلاس Blog درکدهای برنامه درنظر گرفته نشود، یک مقدار پیش فرض حداقل به آن انتساب داده خواهد شد (چون value type است). بنابراین نیاز است این خاصیت را از نوع nullable تعریف کرد (public DateTime? Inserted).

یک نکته: در حالت DatabaseGeneratedOption.Identity و یا ValueGeneratedOnAdd فوق، اگر مقداری به این نوع فیلدها انتساب داده شده باشد که با مقدار پیش فرض آن‌ها (property.ClrType.GetDefaultValue) متفاوت باشد، از این مقدار جدید، بجای تولید مقداری خودکار، استفاده خواهد شد. برای مثال مقدار پیش فرض رشته‌ها، نال، مقادیر عددی، صفر و برای Guid مقدار Guid.Empty است. اگر هر مقدار دیگری بجای این‌ها به فیلدهای فوق انتساب داده شوند، از آن‌ها استفاده می‌شود.

ج) تولید داده‌های خودکار در هر دو حالت Add و Update
تولید داده‌ها در حالت‌های Add و Update به این معنا است که یک چنین خواصی، همواره با فراخوانی متد SaveChanges، دارای مقدار خودکار جدیدی خواهند شد و نیازی نیست در کدها مقدار دهی شوند. برای مشخص سازی این نوع خواص، از ویژگی DatabaseGenerated با مقدار Computed و یا متد ValueGeneratedOnAddOrUpdate در حالت Fluent API می‌توان استفاده کرد:
public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public DateTime LastUpdated { get; set; }
}
و یا معادل این تنظیم با استفاده از Fluent API به صورت ذیل است:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
       .Property(b => b.LastUpdated)
       .ValueGeneratedOnAddOrUpdate();
}
همانطور که پیشتر نیز عنوان شد، تولید خودکار مقادیر فیلدها فقط در حالت‌های int و Guid انجام می‌شود (که برای مثال SQL Server از آن‌ها پشتیبانی می‌کند). در مثال فوق، خاصیت LastUpdated از نوع DateTime اینگونه تعریف شده‌است و SQL Server برای یک چنین فیلدهای خاصی، مقدار خودکاری را تولید نکرده و به دنبال مقدار پیش فرض آن می‌گردد. بنابراین در اینجا نیز باید مشخص سازی HasDefaultValueSql("getdate()") را که در قسمت قبل عنوان کردیم، صراحتا در قسمت تنظیمات Fluent API ذکر و تنظیم کرد.

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


خواص محاسباتی (Computed Columns) و تفاوت آن‌ها با DatabaseGeneratedOption.Computed

خواص محاسباتی (Computed Columns)، خواصی هستند که مقادیر آن‌ها در بانک اطلاعاتی محاسبه می‌شوند و کاملا متفاوت هستند با DatabaseGeneratedOption.Computed که مفهوم دیگری دارد. DatabaseGeneratedOption.Computed به این معنا است که این فیلد خاص، با هر بار فراخوانی SaveChanges باید مقدار محاسبه شده‌ی جدیدی را داشته باشد و روش تولید این مقدار خودکار، یا بر اساس Guidهای سری است، یا توسط فیلدهای خود افزاینده‌ی عددی و یا از طریق مقادیر پیش فرضی مانند getdate در حین ثبت یا به روز رسانی، مقدار دهی می‌شوند. اما خواص محاسباتی، یکی از امکانات «گزارشگیری سریع» SQL Server هستند و به نحو ذیل، تنها توسط Fluent API قابل تنظیم می‌باشند:
public class Person
{
    public int PersonId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string DisplayName { get; set; }
}

public class MyContext : DbContext
{
    public DbSet<Person> People { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
          modelBuilder.Entity<Person>()
              .Property(p => p.DisplayName)
               .HasComputedColumnSql("[LastName] + ', ' + [FirstName]");
     }
 }
در اینجا فیلد DisplayName یک فیلد محاسباتی بوده و از حاصل جمع دو فیلد دیگر در سمت دیتابیس تشکیل می‌شود. این نگاشت و محاسبه چون در سمت بانک اطلاعاتی انجام می‌شود، بازدهی بیشتری دارد نسبت به حالتی که ابتدا دو فیلد به کلاینت منتقل شده و سپس در این سمت جمع زده شوند.


امکان تعریف Sequence در EF Core 1.0

Sequence قابلیتی است که به SQL Server 2012 اضافه شده‌است و توضیحات بیشتر آن‌را در مطلب «نحوه ایجاد Sequence و استفاده آن در Sql Server 2012» می‌توانید مطالعه کنید.
در EF Core، امکان مدلسازی Sequence نیز پیش بینی شده‌است. آن‌ها به صورت پیش فرض در مدل‌ها ذکر نمی‌شوند و همچنین وابستگی به جدول خاصی ندارند. به همین جهت امکان تعریف آن‌ها صرفا توسط Fluent API وجود دارد:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
     modelBuilder.HasSequence<int>("OrderNumbers", schema: "shared") 
           .StartsAt(1000).IncrementsBy(5);

     modelBuilder.Entity<Order>()
         .Property(o => o.OrderNo)
         .HasDefaultValueSql("NEXT VALUE FOR shared.OrderNumbers");
}
پس از اینکه یک Sequence  تعریف شد، می‌توان برای نمونه از آن جهت تولید مقادیر پیش فرض ستون‌ها استفاده کرد.
در مثال فوق، ابتدا یک Sequence نمونه به نام OrderNumbers تعریف شده‌است که از عدد 1000 شروع شده و واحد افزایش آن 5 است. سپس از این نام در قسمت مقدار پیش فرض ستون OrderNo استفاده شده‌است.

و یا از Sequence ‌ها می‌توان برای تعیین مقدار پیش فرض Primary key بجای حالت identity خود افزایش یابنده استفاده کرد:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.HasSequence<int>("PrimaryKeyWithSequenceSequence");
    modelBuilder.Entity<PrimaryKeyWithSequence>(entity =>
     {
       entity.Property(e => e.PrimaryKeyWithSequenceId).HasDefaultValueSql("NEXT VALUE FOR [PrimaryKeyWithSequenceSequence]");
     });
}
در اینجا یک توالی از نوع int تعریف شده و سپس هربار که قرار است رکوردی درج شود، مقدار id آن به صورت خودکار از طریق کوئری Select NEXT VALUE FOR
[PrimaryKeyWithSequenceSequence] دریافت و سپس بجای فیلد id درج می‌شود.

به این روش الگوریتم Hi-Low هم می‌گویند که یکی از مهم‌ترین اهداف آن داشتن یک سری Id منحصربفرد، جهت بالابردن سرعت insertها در یک batch است. در حالت عادی insertها، ابتدا یک insert انجام می‌شود، سپس کوئری گرفته شده و آخرین Id درج شده به کلاینت بازگشت داده می‌شود. این روش، برای انجام تنها یک insert، سریع است. اما برای batch insert، به شدت کارآیی پایینی دارد. به همین جهت دسترسی به بازه‌ای از اعداد منحصربفرد، پیش از شروع به insert تعداد زیادی رکورد، سرعت نهایی کار را بالا می‌برد.


نحوه‌ی تعریف ایندکس‌ها در EF Core 1.0

برای افزودن ایندکس‌ها به EF Core 1.0، تنها روش میسر، استفاده از Fluent API است (و برخلاف EF 6.x از روش data annotations فعلا پشتیبانی نمی‌کند؛ هرچند API جدید آن نسبت به EF 6.x بسیار واضح‌تر است و با ابهامات کمتر).
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
      modelBuilder.Entity<Blog>()
          .HasIndex(b => b.Url)
          .HasName("Index_Url");
اگر قسمت HasName را ذکر نکنید، نام آن <IX_<type name>_<property name درنظر گرفته می‌شود و برای اینکه ایندکس منحصربفردی را تعریف کنید، می‌توان متد IsUnique را به انتهای این زنجیره اضافه کرد:
 modelBuilder.Entity<Blog>().HasIndex(b => b.Url).HasName("Index_Url").IsUnique();
همچنین می‌توان همانند composite keys، در اینجا نیز ترکیبی از خواص را به صورت یک ایندکس معرفی نمود:
modelBuilder.Entity<Person>()
   .HasIndex(idx => new { idx.FirstName, idx.LastName })
   .IsUnique();
در این حالت اگر HasName ذکر نشود، نام آن همانند الگویی است که پیشتر عنوان شد؛ با این تفاوت که قسمت property name آن، جمع نام تمام خواص ذکر شده و جدا شده‌ی با _ خواهد بود.

یک نکته: اگر از پروایدر SQL Server استفاده می‌کنید، می‌توان متد الحاقی ویژه‌ای را به نام ForSqlServerIsClustered نیز برای تعریف clustered indexes، در این زنجیره ذکر کرد.


امکان تعریف Alternate Keys در EF Core 1.0

به Unique Constraints در EF Core، نام Alternate Keys را داده‌اند و این مورد نیز تنها از طریق Fluent API قابل تنظیم است:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
   modelBuilder.Entity<Car>()
     .HasAlternateKey(c => c.LicensePlate)
     .HasName("AlteranteKey_LicensePlate");
}
برای یک Alternate Key به صورت خودکار هم ایندکس ایجاد می‌شود و هم اینکه این ایندکس منحصربفرد خواهد بود.
اگر متد HasName در اینجا ذکر نشود، نام پیش فرض آن  <type name>_<property name> خواهد بود و اگر همانند composite keys و یا ایندکس‌های ترکیبی، چند خاصیت ذکر شوند، قسمت property name به جمع نام تمام خواص ذکر شده و جدا شده‌ی با _ تنظیم می‌شود.
برای نمونه اگر یک Alternate Key ترکیبی را به صورت ذیل تعریف کنیم:
modelBuilder.Entity<Person>()
     .HasAlternateKey(x => new { x.FirstName, x.LastName });
در قسمت مهاجرت‌هایی که قرار است به بانک اطلاعاتی اعمال شوند، به یک UniqueConstraint ترجمه می‌شود:
 table.UniqueConstraint("AK_Persons_FirstName_LastName", x => new { x.FirstName, x.LastName });


سؤال: یک Unique Constraint با Unique Index چه تفاوتی دارد؟

در پشت صحنه، پیاده سازی یک Unique Constraint با Unique Index تفاوتی ندارند. فقط از دیدگاه روشن‌تر شدن مقصود، استفاده‌ی از Unique Constraint ترجیح داده می‌شود.
البته از دیدگاه بانک اطلاعاتی پیاده سازی کننده نیز برای نمونه SQL Server، این تفاوت‌ها وجود دارند:
الف) یک Unique Constraint را نمی‌توان غیرفعال کرد؛ برخلاف Unique Indexها.
ب) Unique Constraint‌ها موارد اضافه‌تری را مانند FILLFACTOR و IGNORE_DUP_KEY نیز می‌توانند تنظیم کنند.
ج) امکان تعریف فیلترها برای Unique Indexها وجود دارد؛ برخلاف Unique Constraint ها.

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

ماهیت این پایگاه داده وب سرویسی مبتنی بر REST است و فرمت اطلاعاتی که از سرور دریافت می‌شود، JSON است.

گام اول: باید آخرین نسخه RavenDB  را دریافت کنید. همان طور که مشاهده می‌کنید، ویرایش‌های مختلف کتابخانه هایی که برای نسخه Client و همچنین Server طراحی شده است، دراین فایل قرار گرفته است.

برای راه اندازی Server باید فایل Start را اجرا کنید، چند ثانیه بعد محیط مدیریتی آن را در مرورگر خود مشاهده می‌کنید. در بالای صفحه روی لینک Databases کلیک کنید و در صفحه باز شده گزینه New Database را انتخاب کنید. با دادن یک نام دلخواه حالا شما یک پایگاه داده ایجاد کرده اید. تا همین جا دست نگه دارید و اجازه دهید با این محیط دوست داشتنی و قابلیت‌های آن بعدا آشنا شویم.
در گام دوم به Visual Studio می‌رویم و نحوه ارتباط با پایگاه داده و استفاده از دستورات آن را فرا می‌گیریم.
 

گام دوم:

با یک پروژه Test شروع می‌کنیم که در هر گام تکمیل می‌شود و می‌توانید پروژه کامل را در پایان این پست دانلود کنید.

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

  • استفاده از NuGet : با استفاده از دستور زیر Package مورد نیاز به پروژه شما افزوده می‌شود.

PM> Install-Package RavenDB -Version 1.0.919 

  • اضافه کردن کتابخانه‌ها به صورت دستی : کتابخانه‌های مورد نیاز شما در همان فایلی که دانلود شده بود و در پوشه Client قرار دارند.

کتابخانه هایی را که NuGet به پروژه من اضافه کرد، در تصویر زیر مشاهده می‌کنید :

با Newtonsoft.Json در اولین بخش بحث آشنا شدید. NLog هم یک کتابخانه قوی و مستقل برای مدیریت Log است که این پایگاه داده از آن بهره برده است.

" دلیل اینکه از پروژه تست استفاده کردم ؛ تمرکز روی کدها و مشاهده تاثیر آن‌ها ، مستقل از UI و لایه‌های دیگر نرم افزار است. بدیهی است که استفاده از آن‌ها در هر پروژه امکان پذیر است. "

برای شروع نیاز به آدرس Server و نام پایگاه داده داریم که می‌توانید در App.config به عنوان تنظیمات نرم افزار شما ذخیره شود و هنگام اجرای نرم افزار مقدار آن‌ها را خوانده و در متغییر‌های readonly ذخیره شوند.

<appSettings>
    <add key="ServerName" value="http://SorousH-HP:8080/"/>
    <add key="DatabaseName" value="TestDatabase" />
</appSettings>

هنگامی که صفحه Management Studio در مرورگر باز است، می‌توانید از نوار آدرس مرورگر خود آدرس سرور را به دست آورید.  

    [TestClass]
    public class BeginnerTest
    {
        private readonly string serverName;
        private readonly string databaseName;

        public BeginnerTest()
        {
            serverName = ConfigurationManager.AppSettings["ServerName"];
            databaseName = ConfigurationManager.AppSettings["DatabaseName"];
        }
    }

برای برقراری ارتباط با پایگاه داده نیاز به یک شئ از جنس DocumentStore و جهت انجام عملیات مختلف ( ذخیره، حذف و ... ) نیاز به یک شئ از جنس IDocumentSession است. کد زیر، نحوه کار با آن‌ها را به شما نشان می‌دهد :

[TestClass]
    public class BeginnerTest
    {
        private readonly string serverName;
        private readonly string databaseName;

        private DocumentStore documentStore;
        private IDocumentSession session;

        public BeginnerTest()
        {
            serverName = ConfigurationManager.AppSettings["ServerName"];
            databaseName = ConfigurationManager.AppSettings["DatabaseName"];
        }

        [TestInitialize]
        public void TestStart()
        {
            documentStore = new DocumentStore { Url = serverName };
            documentStore.Initialize();
            session = documentStore.OpenSession(databaseName);

        }
        
        [TestCleanup]
        public void TestEnd()
        {
             session.SaveChanges(); 
             documentStore.Dispose();
             session.Dispose();
        }
    }

در طراحی این پایگاه داده از اگوی Unit Of Work استفاده شده است. به این معنی که تمام تغییرات در حافظه ذخیره می‌شوند و به محض اجرای دستور ;()session.SaveChanges ارتباط برقرار شده و تمام تغییرات ذخیره خواهند شد.

هنگام شروع ( تابع : TestStart ) متغییر session مقدار دهی می‌شود و در پایان کار ( تابع : TestEnd ) تغییرات ذخیره شده و منابعی که توسط این دو شئ در حافظه استفاده شده است، رها می‌شود.

البته بر مبنای طراحی شما، دستور ;()session.SaveChanges می‌تواند پس از انجام هر عملیات اجرا شود.

برای آشنا شدن با نحوه ذخیره کردن اطلاعات، به کد زیر دقت کنید:
class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Address { get; set; }
        public int Zip { get; set; }اهی 
    }
        [TestMethod]
        public void Insert()
        {
            var user = new User
                           {
                               Id = 1,
                               Name = "John Doe",
                               Address = "no-address",
                               Zip = 65826
                           };
            session.Store(user);
        }
اگر همه چیز درست پیش رفته باشد، وقتی به محیط RavenDB Studio که هنوز در مرورگر شما باز است، نگاهی می‌اندازید، یک سند جدید ایجاد شده است که با کلیک روی آن، اطلاعات آن قابل مشاهده است.
لحظه‌ی لذت بخشی است...
یکی  از روش‌های خواندن اطلاعات هم به صورت زیر است:
        [TestMethod]
        public void Select()
        {
            var user = session.Load<User>(1);
        }
نتیجه خروجی این دستور هم یک شئ از جنس کلاس User است.

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

" به شما پیشنهاد می‌کنم که منتظر بحث بعدی نباشید! همین حالا دست به کار شوید... "