نظرات مطالب
VS Code برای توسعه دهندگان ASP.NET Core - قسمت دوم - ایجاد و اجرای اولین برنامه
احتمال دارد که دو نسخه‌ی 32 بیتی و 64 بیتی از دات نت بر روی سیستم شما نصب هست و همچنین مسیر 32 بیتی به اشتباه به path ویندوز اضافه شده. این نسخه‌ی 32 بیتی باید حذف شود. اطلاعات بیشتر
به صورت خلاصه، متغیرهای محیطی ویندوز را باز کنید (System Environment). بعد متغیر Path را بررسی کنید که آیا به مسیر
C:\Program Files (x86)\dotnet
اشاره می‌کند؟ اگر بله، آن‌را به
C:\Program Files\dotnet
ویرایش کنید.
اشتراک‌ها
Bulk delete و Bulk update در Entity framework
در Entity framework به کمک امکانات LINQ، نمی‌توان چندین رکورد را با هم (یکجا) حذف کرد یا به روز رسانی نمود. برای مثال دستوراتی مانند Delete from tbl1 where id>3 و یا update tbl1 set f1=2 where id>3 معادلی در LINQ to EF ندارند. برای انجام اینگونه امور یا باید رویه ذخیره شده نوشت و سپس آن‌را در EF فراخوانی کرد؛ یا دستورات SQL خام را مستقیما بر روی بانک اطلاعاتی اجرا کرد و یا باید حلقه‌ای را تشکیل داد و موارد موجود را یک به یک ویرایش یا حذف نمود. مورد آخر خصوصا از لحاظ کارآیی به هیچ عنوان پذیرفتنی نیست.
البته اکثر ORMهای موجود از Bulk operations پشتیبانی نمی‌کنند و این مورد منحصر به EF نیست. علت آن هم به مشکل بودن هماهنگ سازی Context و بانک اطلاعاتی، پس از Bulk operations بر می‌گردد. برای مثال در یک کوئری حذف پیچیده، هماهنگ سازی سطح اول کش یا Tracking API با رکوردهای باقی مانده در بانک اطلاعاتی کار ساده‌ای نیست و اگر اینکار به نحو صحیحی صورت نگیرد، کاربران در حین ذخیره سازی اطلاعات ممکن است با خطاهای همزمانی متوقف شوند (چون هنوز رکوردهای حذف شده در سطح اول کش یا Context وجود دارند، ORM تصور می‌کند کاربر دیگری اطلاعات را حذف کرده است و یک استثنای همزمانی را صادر خواهد کرد).


معرفی Entity Framework Extended Library

کتابخانه «Entity Framework Extended Library» تعدادی متد الحاقی را به EF جهت اعمال Bulk delete و Bulk update سازگار با کوئری‌های تهیه شده به وسیله امکانات LINQ to EF، اضافه می‌کند. البته این کتابخانه امکانات دیگری مانند Future Queries (یکی کردن چند کوئری متفاوت LINQ جهت اجرا در یک رفت و برگشت به بانک اطلاعاتی)، Query Result Cache (سطح دوم کش) را نیز به همراه دارد.
Bulk delete و Bulk update در Entity framework
مطالب
آشنایی با NHibernate - قسمت دوم

آزمون واحد کلاس نگاشت تهیه شده

در مورد آشنایی با آزمون‌های واحد لطفا به برچسب مربوطه در سمت راست سایت مراجعه بفرمائید. همچنین در مورد اینکه چرا به این نوع API کلمه Fluent اطلاق می‌شود، می‌توان به تعریف آن جهت مطالعه بیشتر مراجعه نمود.

در این قسمت قصد داریم برای بررسی وضعیت کلاس نگاشت تهیه شده یک آزمون واحد تهیه کنیم. برای این منظور ارجاعی را به اسمبلی nunit.framework.dll به پروژه UnitTests که در ابتدای کار به solution جاری در VS.Net افزوده بودیم، اضافه نمائید (همچنین ارجاع‌هایی به اسمبلی‌های پروژه NHSample1 ، FluentNHibernate ، System.Data.SQLite ، NHibernate.ByteCode.Castle و Nhibernate نیز نیاز هستند). تمام اسمبلی‌های این فریم ورک‌ها از پروژه FluentNHibernate قابل استخراج هستند.

سپس سه کلاس زیر را به پروژه آزمون واحد اضافه خواهیم کرد.
کلاس TestModel : (جهت مشخص سازی محل دریافت اطلاعات نگاشت)

using FluentNHibernate;
using NHSample1.Domain;

namespace UnitTests
{
public class TestModel : PersistenceModel
{
public TestModel()
{
AddMappingsFromAssembly(typeof(CustomerMapping).Assembly);
}
}
}

کلاس FixtureBase : (جهت ایجاد سشن NHibernate در ابتدای آزمون واحد و سپس پاکسازی اشیاء در پایان کار)

using NUnit.Framework;
using NHibernate;
using FluentNHibernate;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;

namespace UnitTests
{
public class FixtureBase
{
protected SessionSource SessionSource { get; set; }
protected ISession Session { get; private set; }

[SetUp]
public void SetupContext()
{
var cfg = Fluently.Configure().Database(SQLiteConfiguration.Standard.InMemory);

SessionSource = new SessionSource(
cfg.BuildConfiguration().Properties,
new TestModel());

Session = SessionSource.CreateSession();
SessionSource.BuildSchema(Session);
}

[TearDown]
public void TearDownContext()
{
Session.Close();
Session.Dispose();
}
}
}

و کلاس CustomerMapping_Fixture.cs : (جهت بررسی صحت نگاشت تهیه شده با کمک دو کلاس قبل)

using NUnit.Framework;
using FluentNHibernate.Testing;
using NHSample1.Domain;

namespace UnitTests
{
[TestFixture]
public class CustomerMapping_Fixture : FixtureBase
{
[Test]
public void can_correctly_map_customer()
{
new PersistenceSpecification<Customer>(Session)
.CheckProperty(c => c.Id, 1001)
.CheckProperty(c => c.FirstName, "Vahid")
.CheckProperty(c => c.LastName, "Nasiri")
.CheckProperty(c => c.AddressLine1, "Addr1")
.CheckProperty(c => c.AddressLine2, "Addr2")
.CheckProperty(c => c.PostalCode, "1234")
.CheckProperty(c => c.City, "Tehran")
.CheckProperty(c => c.CountryCode, "IR")
.VerifyTheMappings();
}
}
}

توضیحات:
اکنون به عنوان یک برنامه نویس متعهد نیاز است تا کار صورت گرفته در قسمت قبل را آزمایش کنیم.
کار بررسی صحت نگاشت تعریف شده در قسمت قبل توسط کلاس استاندارد PersistenceSpecification فریم ورک FluentNHibernate انجام خواهد شد (در کلاس CustomerMapping_Fixture). این کلاس برای انجام عملیات آزمون واحد نیاز به کلاس پایه دیگری به نام FixtureBase دارد که در آن کار ایجاد سشن NHibernate (در قسمت استاندارد SetUp آزمون واحد) و سپس آزاد سازی آن را در هنگام خاتمه کار ، انجام می‌دهد (در قسمت TearDown آزمون واحد).
این ویژگی‌ها که در مباحث آزمون واحد نیز به آن‌ها اشاره شده است، سبب اجرای متدهایی پیش از اجرا و بررسی هر آزمون واحد و سپس آزاد سازی خودکار منابع خواهند شد.
برای ایجاد یک سشن NHibernate نیاز است تا نوع دیتابیس و همچنین رشته اتصالی به آن (کانکشن استرینگ) مشخص شوند. فریم ورک Fluent NHibernate با ایجاد کلاس‌های کمکی برای این امر، به شدت سبب ساده‌ سازی انجام آن شده است. در این مثال، نوع دیتابیس به SQLite و در حالت دیتابیس در حافظه (in memory)، تنظیم شده است (برای انجام امور آزمون واحد با سرعت بالا).
جهت اجرای هر دستوری در NHibernate نیاز به یک سشن می‌باشد. برای تعریف شیء سشن، نه تنها نیاز به مشخص سازی نوع و حالت دیتابیس مورد استفاده داریم، بلکه نیاز است تا وهله‌ای از کلاس استاندارد PersistanceModel را نیز جهت مشخص سازی کلاس نگاشت مورد استفاده مشخص نمائیم. برای این منظور کلاس TestModel فوق تعریف شده است تا این نگاشت را از اسمبلی مربوطه بخواند و مورد استفاده قرار دهد (بر پایی اولیه این مراحل شاید در ابتدای امر کمی زمانبر باشد اما در نهایت یک پروسه استاندارد است). توسط این کلاس به سیستم اعلام خواهیم کرد که اطلاعات نگاشت را باید از کدام کلاس دریافت کند.
تا اینجای کار شیء SessionSource را با معرفی نوع دیتابیس و همچنین محل دریافت اطلاعات نگاشت اشیاء معرفی کردیم. در دو سطر بعدی متد SetupContext کلاس FixtureBase ، ابتدا یک سشن را از این منبع سشن تهیه می‌کنیم. شیء منبع سشن در این فریم ورک در حقیقت یک factory object است (الگوهای طراحی برنامه نویسی شیءگرا) که امکان دسترسی به انواع و اقسام دیتابیس‌ها را فراهم می‌سازد. برای مثال اگر روزی نیاز بود از دیتابیس اس کیوال سرور استفاده شود، می‌توان از کلاس MsSqlConfiguration بجای SQLiteConfiguration استفاده کرد و همینطور الی آخر.
در ادامه توسط شیء SessionSource کار ساخت database schema را نیز به صورت پویا انجام خواهیم داد. بله، همانطور که متوجه شده‌اید، کار ساخت database schema نیز به صورت پویا توسط فریم ورک NHibernate با توجه به اطلاعات کلاس‌های نگاشت، صورت خواهد گرفت.

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

در ادامه اگر آزمون واحد را اجرا نمائیم (متد can_correctly_map_customer در کلاس CustomerMapping_Fixture)، نتیجه باید شبیه به شکل زیر باشد:



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

نکته:
شاید سؤال بپرسید که در تابع can_correctly_map_customer عملا چه اتفاقاتی رخ داده است؟ برای بررسی آن در متد SetupContext کلاس FixtureBase ، اولین سطر آن‌را به صورت زیر تغییر دهید تا عبارات SQL نهایی تولید شده را نیز بتوانیم در حین عملیات تست مشاهده نمائیم:

var cfg = Fluently.Configure().Database(SQLiteConfiguration.Standard.ShowSql().InMemory);




مطابق متد تست فوق، عبارات تولید شده به شرح زیر هستند:

NHibernate: select next_hi from hibernate_unique_key
NHibernate: update hibernate_unique_key set next_hi = @p0 where next_hi = @p1;@p0 = 2, @p1 = 1
NHibernate: INSERT INTO "Customer" (FirstName, LastName, AddressLine1, AddressLine2, PostalCode, City, CountryCode, Id) VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7);@p0 = 'Vahid', @p1 = 'Nasiri', @p2 = 'Addr1', @p3 = 'Addr2', @p4 = '1234', @p5 = 'Tehran', @p6 = 'IR', @p7 = 1001
NHibernate: SELECT customer0_.Id as Id0_0_, customer0_.FirstName as FirstName0_0_, customer0_.LastName as LastName0_0_, customer0_.AddressLine1 as AddressL4_0_0_, customer0_.AddressLine2 as AddressL5_0_0_, customer0_.PostalCode as PostalCode0_0_, customer0_.City as City0_0_, customer0_.CountryCode as CountryC8_0_0_ FROM "Customer" customer0_ WHERE customer0_.Id=@p0;@p0 = 1001

نکته جالب این عبارات، استفاده از کوئری‌های پارامتری است به صورت پیش فرض که در نهایت سبب بالا رفتن امنیت بیشتر برنامه (یکی از راه‌های جلوگیری از تزریق اس کیوال در ADO.Net که در نهایت توسط تمامی این فریم ورک‌ها در پشت صحنه مورد استفاده قرار خواهند گرفت) و همچنین سبب بکار افتادن سیستم‌های کش دیتابیس‌های پیشرفته مانند اس کیوال سرور می‌شوند (execution plan کوئری‌های پارامتری در اس کیوال سرور جهت بالا رفتن کارآیی سیستم کش می‌شوند و اهمیتی هم ندارد که حتما رویه ذخیره شده باشند یا خیر).

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

نظرات مطالب
ایجاد ایندکس منحصربفرد بر روی چند فیلد با هم در EF Code first
- EF جزو خانواده‌ی ابزارهایی به نام ORMs است. زمانیکه از یک ORM استفاده می‌کنید و مستقیما SQL نویسی نمی‌کنید، کدهای شما قابل انتقال می‌شوند. می‌توانید به سادگی بانک اطلاعاتی برنامه را عوض کنید بدون اینکه نیازی باشد در کدهای اصلی برنامه تغییری حاصل شود. اهمیت این مساله در اینجا است که نهایتا پروایدر آن بانک اطلاعاتی خاص، بر اساس تعاریف برنامه و ORM مورد استفاده می‌داند که چگونه باید SQL صحیح و مرتبطی را تولید کند که ممکن است از یک بانک اطلاعاتی به بانک اطلاعاتی دیگری متفاوت باشد.
- فعلا از طریق ویژگی فوق پشتیبانی نمی‌شود.
مطالب
معرفی برنامه‌ی Subtitle Tools

این روزها زیرنویس‌های فارسی فیلم‌های روز دنیا را راحت می‌شود در اینترنت یافت، اما مشکلات زیادی هم به همراه این نوع فایل‌ها وجود دارند:
- گاها با فیلم دریافت شده هماهنگ نیستند.
- عموما با فرمت windows-1256 تهیه می‌شوند که برای استفاده از آن‌ها در سیستم‌های مختلف بهتر است به UTF8 تبدیل شوند.
- اکثر برنامه‌های موجود برای کار با زیر نویس‌ها و ویرایش آن‌ها، درکی از یونیکد ندارند.
- عموما نیاز است جهت استفاده از آن‌ها در یک جمع، تعدادی از سطور آن‌ها را با حفظ شماره بندی فایل، حذف کرد!
و ...

به همین جهت نیاز به یک برنامه‌ی جمع و جور جهت کار با زیر نویس‌ها داشتم که نتیجه‌ی آن تهیه‌ی برنامه‌ی زیر شد:

الف) تغییر encoding فایل دریافتی به UTF-8
هنگام گشودن اکثر فایل‌های زیر نویس فارسی با تصویر زیر روبرو خواهید شد:



برای تبدیل آن به فرمت یونیکد تنها کافی است بر روی دکمه‌ی To UTF-8 کلیک کنید. در این حالت نتیجه به صورت زیر خواهد بود:



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



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

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



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



در این حالت اگر نیاز است سطری حذف شود، آن‌را انتخاب نموده و بر روی دکمه‌ی Delete row کلیک نمائید. در این حالت علاوه بر حذف ردیف، کلیه شماره‌های موجود در زیر نویس نیز به صورت خودکار مجددا تولید و مرتب خواهند شد. (کلیک راست بر روی هر ردیف نیز این گزینه‌ را نمایش می‌دهد)
یا اگر مشغول به ویرایش متنی شدید، پس از ویرایش، کلیک کردن بر روی دکمه‌ی Save را فراموش نکنید (در حالت حذف نیازی به اینکار نیست).

ز) پیدا کردن زیرنویس یک فایل بر اساس امضای دیجیتال آن
سایت opensubtitles.org یک API را جهت پیدا کردن زیرنویسی مطابق با هش یک فایل ویدیویی ارائه داده است، که در برنامه‌ی جاری، کلاینتی برای آن تهیه شده است:



فقط کافی است فایل ویدیویی خود را در این قسمت انتخاب نمائید. برنامه هش فایل را محاسبه کرده و سپس با کمک سرویس XML-RPC سایت opensubtitles.org سعی در یافتن زیرنویس هماهنگ با آن خواهد کرد. در اینجا دیگر مهم نیست نام فایل انتخابی چیست؛ امضای دیجیتال آن مهم است. برای دریافت موارد مورد نظر، ابتدا آن‌ها را تیک زده و سپس بر روی دکمه‌ی دریافت کلیک کنید. کلیک راست بر روی ردیف مورد نظر نیز این امکان دریافت را لحاظ کرده است.
همچنین قسمتی هم برای آپلود زیرنویس به این سایت پیش بینی شده است (لطفا مصرف کننده‌ی صرف یا به قولی لیچر نباشید!)



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

پیشنیاز استفاده از این برنامه، نصب دات نت فریم ورک 4 است که اگر از ویندوز 7 استفاده می‌کنید، جزو به روز رسانی‌های اختیاری آن است و در حالت کلی نسخه‌ی کامل 32 بیتی و 64 بیتی آن از این آدرس قابل دریافت است.