Manage events entities is pretty easy. You define few informations like a subject, a content, and maybe the most important, dates (a start and a end date of course).
You’re ready to create calendar or timeline features. Baooom! Now you need to be able to create recurrent event ! And everything is going to break.
I’ve work on this kind of feature, and here are my small advices
in this article, I will show how to take a medium-small demo app written using Visual Studio 2013, ASP.NET 4.5, VC 5, and Entity Framework 6 and turn it into a working ASP.NET 5 app employing Visual Studio 2015, MVC 6 and Entity Framework 7. And the new app will happily run on either the .NET 4.6 CLR or the .NET Core CLR. Let's get started.
مطالب
LocalDB FAQ
SQL Server Express LocalDB یا به صورت خلاصه LocalDB، یک بانک اطلاعاتیاست که به صورت متصل به پروسهی برنامهی جاری اجرا میشود؛ برخلاف رویهی متداول بانکهای اطلاعاتی که به صورت یک سرویس مستقل اجرا میشوند. هدف آن، جایگزین کردن نگارش Express نیست و بیشتر حجم کم و سهولت توزیع آن مدنظر بودهاست. برای مثال نگارش Express به صورت یک سرویس مجزا و مستقل بر روی سیستم نصب میشود؛ اما LocalDB به همراه و متصل به برنامهی نوشته شده، اجرا میشود:
اگر به تصویر فوق دقت کنید، یک child process جدید به نام sqlservr.exe نیز به همراه برنامهی آزمایشی ما به صورت خودکار اجرا شدهاست. این child process به همراه پارامترهای ذیل است (که توسط NET Framework. مقدار دهی میشوند و مدیریت نهایی آن خودکار است):
بنابراین LocalDB برخلاف SQL Server CE، یک بانک اطلاعاتی in-process نیست و به صورت یک پروسهی مجزا اجرا میشود. زمانیکه از SQL Server CE استفاده میشود، موتور این بانک اطلاعاتی چند فایل DLL بیشتر نیستند و نهایتا اجرای آن داخل پروسهی برنامهی ما و همانند اجرای سایر DLLهای متصل و مورد استفادهی به آن است.
اما LocalDB یک بانک اطلاعاتی user-mode است و در پروفایل کاربر جاری سیستم اجرا میشود. این بانک اطلاعاتی یک بار بر روی سیستم نصب میشود و در هر برنامهای که از آن استفاده میکنید، یک child process مجزای خاص خودش را (sqlservr.exe) اجرا خواهد کرد. اجرا و خاتمهی این child processها نیز خودکار هستند و نیازی به دخالت مستقیم برنامه ندارند.
البته به نظر توسعهی SQL Server CE متوقف شدهاست و دیگر پشتیبانی نمیشود. بنابراین گزینهی ترجیح داده شدهی برای کارهایی با حجمهای بانک اطلاعاتی زیر 10 گیگابایت ، میتواند LocalDB باشد. به علاوه اینکه قابلیتهای T-SQL بیشتری را نیز پشتیبانی میکند و همچنین پشتیبانی منظمی نیز از آن وجود دارد. برای مثال پیش نمایش نگارش 2016 آن نیز موجود است.
در ادامه، یک سری پرسش و پاسخ متداول جهت کار با LocalDB را مرور خواهیم کرد.
محل دریافت آخرین نگارش مستقل آن کجاست؟
همانطور که عنوان شد، یکی از مهمترین اهداف LocalDB، سهولت توزیع آن است و عدم نیاز به یک Admin سیستم، برای نصب و نگهداری آن. نگارش 2014 SP1 آنرا از آدرس ذیل میتوانید دریافت کنید:
https://www.microsoft.com/en-us/download/details.aspx?id=46697
در اینجا نسخههای متعددی وجود دارند. برای مثال اگر سیستم شما 64 بیتی است، تنها نیاز است ENU\x64\SqlLocalDB.msi را دریافت و نصب کنید:
پارامترهای نصب خاموش آن برای توزیع سادهی برنامه کدامند؟
اگر میخواهید نصاب LocalDB را به همراه setup برنامهی خود توزیع کنید، میتوانید روش توزیع خاموش را با ذکر پارامترهای ذیل، مورد استفاده قرار دهید:
رشتهی اتصالی مخصوص آن کدام است؟
اگر نگارش 2014 SP1 آنرا نصب کرده باشید، رشتهی اتصالی فوق، تمام آنچیزی است که برای شروع به کار با آن، نیاز دارید و دارای دو قسمت مهم است:
الف) ذکر وهلهی مدنظر
در اینجا وهلهی MSSQLLocalDB ذکر شدهاست؛ اما چه وهلههایی بر روی سیستم نصب هستند و چطور میتوان وهلهی دیگری را ایجاد کرد؟ برای این منظور، به پارامترهای sqlservr.exe ابتدای بحث دقت کنید. اکثر آنها به پوشهی ذیل اشاره میکنند:
با یک چنین محتوایی
به علاوه، این لیست را توسط برنامهی کمکی SqlLocalDB.exe، به همراه پارامتر info یا i نیز میتوانید دریافت و بررسی کنید:
برنامهی کمکی SqlLocalDB.exe به همراه نصاب LocalDB، نصب میشود و توسط آن میتوان نگارشهای مختلف نصب شدهرا با پارامتر v و وهلهی مختلف موجود را با پارامتر i مشاهده کرد.
همچنین اگر میخواهید وهلهی جدیدی را بجز وهلهی پیش فرض MSSQLLocalDB ایجاد کنید، میتوانید از پارامتر create آن به نحو ذیل استفاده نمائید:
ب) ذکر DataDirectory
در رشتهی اتصالی فوق، پارامتر DataDirectory نیز ذکر شدهاست تا بتوان مسیر بانک اطلاعاتی را به صورت نسبی و بدون ذکر عبارت دقیق آن که ممکن است در سیستمهای دیگر متفاوت باشد، پردازش کرد. این پارامتر در برنامههای وب به پوشهی استاندارد app_data اشاره میکند و نیازی به تنظیم اضافهتری ندارد. اما در برنامههای دسکتاپ باید به نحو ذیل به صورت دستی، در آغاز برنامه مقدار دهی شود:
به این ترتیب DataDirectory به محل قرارگیری فایل exe برنامه اشاره میکند. بدیهی است در اینجا هر پوشهی دیگری را نیز میتوانید ذکر کنید:
برای نمونه تنظیم فوق به زیر پوشهی db، در کنار فایل exe برنامه اشاره میکند.
محل نصب بانکهای اطلاعاتی پیش فرض آن کدام است؟
ذکر AttachDbFilename در رشتهی اتصالی فوق، اختیاری است. در صورت عدم ذکر آن، بانک اطلاعاتی ایجاد شده را در یکی از مسیرهای ذیل میتوانید جستجو کنید:
همچنین در این محلها فایلهای log متنی خطاهای این بانک اطلاعاتی را نیز میتوان مشاهده کرد. بنابراین اگر به خطای خاصی برخوردید، بهترین کار، بررسی این فایلها است.
آیا میتوان فایلهای mdf و ldf آنرا به نگارش کامل SQL Server متصل (attach) کرد؟
بله. اما باید دقت داشته باشید که SQL Server به محض اتصال یک بانک اطلاعاتی با نگارش پایینتر به آن، ابتدا شماره نگارش آنرا به روز میکند. یعنی دیگر نخواهید توانست این بانک اطلاعاتی را با نگارش پایینتر LocalDB باز کنید و یک چنین پیام خطایی را دریافت خواهید کرد:
چگونه محتوای بانکهای اطلاعاتی LocalDB را با VS.NET مشاهده کنیم؟
از منوی view گزینهی server explorer را انتخاب کنید. بر روی data connections کلیک راست کرده و گزینهی Add connection را انتخاب کنید.
در صفحهی باز شده، گزینهی Microsoft SQL server را انتخاب کنید. در صفحهی بعد، ذکر server name مطابق data source رشتهی اتصالی بحث شده و سپس انتخاب گزینهی attach a database file کفایت میکند:
پس از کلیک بر روی ok، امکان کار با اجزای این بانک اطلاعاتی را خواهید داشت:
چگونه از LocalDB با EF استفاده کنیم؟
EF 6.x به صورت پیش فرض از بانک اطلاعاتی LocalDB استفاده میکند و تنها داشتن یک چنین تنظیمی در فایل کانفیگ برنامه، برای کار با آن کافی است:
یک قسمت آن ذکر رشتهی اتصالی است که در مورد آن بحث شد و قسمت دوم آن، ذکر connection factory مخصوص localdb است که به صورت فوق میباشد. تنظیم دیگری برای کار با LocalDB و EF 6.x نیازی نیست.
البته باید دقت داشت که اسمبلی EntityFramework.SqlServer نیز به صورت خودکار به همراه بستهی نیوگت EF 6.x به برنامه اضافه میشود که استفادهی از connection factory ذکر شده را میسر میکند.
استفادهی از LocalDB به همراه برنامههای وب چگونه است؟
سه نکته را باید در حین استفادهی از LocalDB، در برنامههای وب اجرا شدهی بر روی IIS مدنظر داشت:
الف) LocalDB یک بانک اطلاعاتی user-mode است و child process آن تحت مجوز اکانت تنظیم شدهی برای آن کار میکند.
ب) همانطور که عنوان شد، در رشتهی اتصالی ذکر شده، پارامتر DataDirectory به پوشهی استاندارد app_data اشاره میکند که فایلهای قرار گرفتهی در آن توسط IIS محافظت میشوند و از طریق وب قابل دسترسی و دانلود نیستند.
ج) child process مربوط به LocalDB، نیاز به دسترسی write، برای کار با فایلهای mdf و ldf خود دارد.
برای مورد الف نیاز است تا به تنظیمات application pool برنامه مراجعه کرده و سپس بر روی آن کلیک راست کرد و گزینهی advanced settings را انتخاب نمود. در اینجا گزینهی load user profile باید true باشد:
تنظیم load user profile ضروری است اما کافی نیست. پس از آن باید setProfileEnvironment را نیز به true تنظیم کرد. تنظیم این مورد در کنسول مدیریتی IIS به صورت زیر است.
ابتدا ریشهی اصلی سرور را انتخاب کنید و سپس به configuration editor آن وارد شوید:
در ادامه از دارپ داون آن، گزینهی system.applicationHost و زیر شاخهی applicationPools آنرا انتخاب کنید:
در اینجا application pool defaults و سپس در آن processModel را نیز باز کنید:
اکنون امکان ویرایش setProfileEnvironment را به true خواهید داشت:
پس از این تنظیم، ابتدا بر روی دکمهی apply سمت راست صفحه کلیک کرده و سپس نیاز است یکبار IIS را نیز ریست کنید تا تنظیمات اعمال شوند.
در ادامه برای تنظیم دسترسی write (موارد ب و ج)، ابتدا بر روی پوشهی app_data برنامه، کلیک راست کرده و برگهی security آنرا باز کنید. سپس بر روی دکمهی edit کلیک کرده و در صفحهی باز شده بر روی دکمهی add کلیک کنید تا بتوان به کاربر application pool برنامه دسترسی write داد:
در اینجا iis apppool\TestLocalDB را وارد کرده و بر روی دکمهی check name کلیک کنید.
iis apppool آن که مشخص است. عبارت TestLocalDB نام application pool ایی است که برای برنامهی وب خود ایجاد کردهایم (بهتر است به ازای هر برنامهی وب، یک application pool مجزا تعریف شود).
در اینجا بر روی OK کلیک کرده و به این کاربر جدید اضافه شده، دسترسی full control را بدهید تا برنامه و یوزر آن بتواند فایلهای mdf و ldf را ایجاد کرده و به روز رسانی کنند.
پس از تنظیم load user profile و همچنین set profile environment و دادن دسترسی write به کاربر application pool برنامه، اکنون child process مربوط به local db را میتوان ذیل پروسهی IIS مشاهده کرد و برنامه قادر به استفادهی از LocalDB خواهد بود:
اگر به تصویر فوق دقت کنید، یک child process جدید به نام sqlservr.exe نیز به همراه برنامهی آزمایشی ما به صورت خودکار اجرا شدهاست. این child process به همراه پارامترهای ذیل است (که توسط NET Framework. مقدار دهی میشوند و مدیریت نهایی آن خودکار است):
"C:\Program Files\Microsoft SQL Server\120\LocalDB\Binn\\sqlservr.exe" -c -SMSSQL12E.LOCALDB -sLOCALDB#5657074F -d"C:\Users\Vahid\AppData\Local\Microsoft\Microsoft SQL Server Local DB\Instances\MSSQLLocalDB\master.mdf" -l"C:\Users\Vahid\AppData\Local\Microsoft\Microsoft SQL Server Local DB\Instances\MSSQLLocalDB\mastlog.ldf" -e"C:\Users\Vahid\AppData\Local\Microsoft\Microsoft SQL Server Local DB\Instances\MSSQLLocalDB\error.log"
اما LocalDB یک بانک اطلاعاتی user-mode است و در پروفایل کاربر جاری سیستم اجرا میشود. این بانک اطلاعاتی یک بار بر روی سیستم نصب میشود و در هر برنامهای که از آن استفاده میکنید، یک child process مجزای خاص خودش را (sqlservr.exe) اجرا خواهد کرد. اجرا و خاتمهی این child processها نیز خودکار هستند و نیازی به دخالت مستقیم برنامه ندارند.
البته به نظر توسعهی SQL Server CE متوقف شدهاست و دیگر پشتیبانی نمیشود. بنابراین گزینهی ترجیح داده شدهی برای کارهایی با حجمهای بانک اطلاعاتی زیر 10 گیگابایت ، میتواند LocalDB باشد. به علاوه اینکه قابلیتهای T-SQL بیشتری را نیز پشتیبانی میکند و همچنین پشتیبانی منظمی نیز از آن وجود دارد. برای مثال پیش نمایش نگارش 2016 آن نیز موجود است.
در ادامه، یک سری پرسش و پاسخ متداول جهت کار با LocalDB را مرور خواهیم کرد.
محل دریافت آخرین نگارش مستقل آن کجاست؟
همانطور که عنوان شد، یکی از مهمترین اهداف LocalDB، سهولت توزیع آن است و عدم نیاز به یک Admin سیستم، برای نصب و نگهداری آن. نگارش 2014 SP1 آنرا از آدرس ذیل میتوانید دریافت کنید:
https://www.microsoft.com/en-us/download/details.aspx?id=46697
در اینجا نسخههای متعددی وجود دارند. برای مثال اگر سیستم شما 64 بیتی است، تنها نیاز است ENU\x64\SqlLocalDB.msi را دریافت و نصب کنید:
پارامترهای نصب خاموش آن برای توزیع سادهی برنامه کدامند؟
اگر میخواهید نصاب LocalDB را به همراه setup برنامهی خود توزیع کنید، میتوانید روش توزیع خاموش را با ذکر پارامترهای ذیل، مورد استفاده قرار دهید:
msiexec /i SqlLocalDB.msi /qn IACCEPTSQLLOCALDBLICENSETERMS=YES
رشتهی اتصالی مخصوص آن کدام است؟
<connectionStrings> <add name="Sample35Context" connectionString="Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\test.mdf;Integrated Security=True;" providerName="System.Data.SqlClient" /> </connectionStrings>
الف) ذکر وهلهی مدنظر
در اینجا وهلهی MSSQLLocalDB ذکر شدهاست؛ اما چه وهلههایی بر روی سیستم نصب هستند و چطور میتوان وهلهی دیگری را ایجاد کرد؟ برای این منظور، به پارامترهای sqlservr.exe ابتدای بحث دقت کنید. اکثر آنها به پوشهی ذیل اشاره میکنند:
C:\Users\your_user_name_here\AppData\Local\Microsoft\Microsoft SQL Server Local DB\Instances
در این پوشه، وهلههای موجود و نصب شدهی بر روی سیستم شما نمایش داده میشوند که یکی از آنها را میتوانید در رشتهی اتصالی فوق ذکر کنید.
به علاوه، این لیست را توسط برنامهی کمکی SqlLocalDB.exe، به همراه پارامتر info یا i نیز میتوانید دریافت و بررسی کنید:
برنامهی کمکی SqlLocalDB.exe به همراه نصاب LocalDB، نصب میشود و توسط آن میتوان نگارشهای مختلف نصب شدهرا با پارامتر v و وهلهی مختلف موجود را با پارامتر i مشاهده کرد.
همچنین اگر میخواهید وهلهی جدیدی را بجز وهلهی پیش فرض MSSQLLocalDB ایجاد کنید، میتوانید از پارامتر create آن به نحو ذیل استفاده نمائید:
For LocalDB SQL EXPRESS 2014 "C:\Program Files\Microsoft SQL Server\120\Tools\Binn\SqlLocalDB.exe" create "v12.0" 12.0 -s For LocalDB SQL Express 2012 "C:\Program Files\Microsoft SQL Server\110\Tools\Binn\SqlLocalDB.exe" create "v11.0" 11.0 -s
ب) ذکر DataDirectory
در رشتهی اتصالی فوق، پارامتر DataDirectory نیز ذکر شدهاست تا بتوان مسیر بانک اطلاعاتی را به صورت نسبی و بدون ذکر عبارت دقیق آن که ممکن است در سیستمهای دیگر متفاوت باشد، پردازش کرد. این پارامتر در برنامههای وب به پوشهی استاندارد app_data اشاره میکند و نیازی به تنظیم اضافهتری ندارد. اما در برنامههای دسکتاپ باید به نحو ذیل به صورت دستی، در آغاز برنامه مقدار دهی شود:
AppDomain.CurrentDomain.SetData("DataDirectory", AppDomain.CurrentDomain.BaseDirectory);
AppDomain.CurrentDomain.SetData("DataDirectory", Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "db"));
محل نصب بانکهای اطلاعاتی پیش فرض آن کدام است؟
ذکر AttachDbFilename در رشتهی اتصالی فوق، اختیاری است. در صورت عدم ذکر آن، بانک اطلاعاتی ایجاد شده را در یکی از مسیرهای ذیل میتوانید جستجو کنید:
C:\Users\USERNAME\AppData\Local\Microsoft\Microsoft SQL Server Local DB\Instances C:\Users\USERNAME\AppData\Local\Microsoft\VisualStudio\SSDT
آیا میتوان فایلهای mdf و ldf آنرا به نگارش کامل SQL Server متصل (attach) کرد؟
بله. اما باید دقت داشته باشید که SQL Server به محض اتصال یک بانک اطلاعاتی با نگارش پایینتر به آن، ابتدا شماره نگارش آنرا به روز میکند. یعنی دیگر نخواهید توانست این بانک اطلاعاتی را با نگارش پایینتر LocalDB باز کنید و یک چنین پیام خطایی را دریافت خواهید کرد:
The database xyz cannot be opened because it is version 706. This server supports version 663 and earlier. A downgrade path is not supported.
چگونه محتوای بانکهای اطلاعاتی LocalDB را با VS.NET مشاهده کنیم؟
از منوی view گزینهی server explorer را انتخاب کنید. بر روی data connections کلیک راست کرده و گزینهی Add connection را انتخاب کنید.
در صفحهی باز شده، گزینهی Microsoft SQL server را انتخاب کنید. در صفحهی بعد، ذکر server name مطابق data source رشتهی اتصالی بحث شده و سپس انتخاب گزینهی attach a database file کفایت میکند:
پس از کلیک بر روی ok، امکان کار با اجزای این بانک اطلاعاتی را خواهید داشت:
چگونه از LocalDB با EF استفاده کنیم؟
EF 6.x به صورت پیش فرض از بانک اطلاعاتی LocalDB استفاده میکند و تنها داشتن یک چنین تنظیمی در فایل کانفیگ برنامه، برای کار با آن کافی است:
<?xml version="1.0" encoding="utf-8"?> <configuration> <configSections> <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> </configSections> <connectionStrings> <add name="Sample35Context" connectionString="Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\test.mdf;Integrated Security=True;" providerName="System.Data.SqlClient" /> </connectionStrings> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup> <entityFramework> <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework"> <parameters> <parameter value="mssqllocaldb" /> </parameters> </defaultConnectionFactory> <providers> <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" /> </providers> </entityFramework> </configuration>
البته باید دقت داشت که اسمبلی EntityFramework.SqlServer نیز به صورت خودکار به همراه بستهی نیوگت EF 6.x به برنامه اضافه میشود که استفادهی از connection factory ذکر شده را میسر میکند.
استفادهی از LocalDB به همراه برنامههای وب چگونه است؟
سه نکته را باید در حین استفادهی از LocalDB، در برنامههای وب اجرا شدهی بر روی IIS مدنظر داشت:
الف) LocalDB یک بانک اطلاعاتی user-mode است و child process آن تحت مجوز اکانت تنظیم شدهی برای آن کار میکند.
ب) همانطور که عنوان شد، در رشتهی اتصالی ذکر شده، پارامتر DataDirectory به پوشهی استاندارد app_data اشاره میکند که فایلهای قرار گرفتهی در آن توسط IIS محافظت میشوند و از طریق وب قابل دسترسی و دانلود نیستند.
ج) child process مربوط به LocalDB، نیاز به دسترسی write، برای کار با فایلهای mdf و ldf خود دارد.
برای مورد الف نیاز است تا به تنظیمات application pool برنامه مراجعه کرده و سپس بر روی آن کلیک راست کرد و گزینهی advanced settings را انتخاب نمود. در اینجا گزینهی load user profile باید true باشد:
تنظیم load user profile ضروری است اما کافی نیست. پس از آن باید setProfileEnvironment را نیز به true تنظیم کرد. تنظیم این مورد در کنسول مدیریتی IIS به صورت زیر است.
ابتدا ریشهی اصلی سرور را انتخاب کنید و سپس به configuration editor آن وارد شوید:
در ادامه از دارپ داون آن، گزینهی system.applicationHost و زیر شاخهی applicationPools آنرا انتخاب کنید:
در اینجا application pool defaults و سپس در آن processModel را نیز باز کنید:
اکنون امکان ویرایش setProfileEnvironment را به true خواهید داشت:
پس از این تنظیم، ابتدا بر روی دکمهی apply سمت راست صفحه کلیک کرده و سپس نیاز است یکبار IIS را نیز ریست کنید تا تنظیمات اعمال شوند.
در ادامه برای تنظیم دسترسی write (موارد ب و ج)، ابتدا بر روی پوشهی app_data برنامه، کلیک راست کرده و برگهی security آنرا باز کنید. سپس بر روی دکمهی edit کلیک کرده و در صفحهی باز شده بر روی دکمهی add کلیک کنید تا بتوان به کاربر application pool برنامه دسترسی write داد:
در اینجا iis apppool\TestLocalDB را وارد کرده و بر روی دکمهی check name کلیک کنید.
iis apppool آن که مشخص است. عبارت TestLocalDB نام application pool ایی است که برای برنامهی وب خود ایجاد کردهایم (بهتر است به ازای هر برنامهی وب، یک application pool مجزا تعریف شود).
در اینجا بر روی OK کلیک کرده و به این کاربر جدید اضافه شده، دسترسی full control را بدهید تا برنامه و یوزر آن بتواند فایلهای mdf و ldf را ایجاد کرده و به روز رسانی کنند.
پس از تنظیم load user profile و همچنین set profile environment و دادن دسترسی write به کاربر application pool برنامه، اکنون child process مربوط به local db را میتوان ذیل پروسهی IIS مشاهده کرد و برنامه قادر به استفادهی از LocalDB خواهد بود:
برای ثبت SQL تولیدی توسط EF، ابزارهای پروفایلر زیادی وجود دارند (+). علاوه بر اینها یک پروایدر سورس باز نیز برای این منظور به نام EFTracingProvider موجود میباشد که برای EF Database first نوشته شده است. در ادامه نحوهی استفاده از این پروایدر را در برنامههای EF Code first مرور خواهیم کرد.
الف) دریافت کدهای EFTracingProvider اصلی: (+)
از کدهای دریافتی این مجموعه، فقط به دو پوشه EFTracingProvider و EFProviderWrapperToolkit آن نیاز است.
ب) اصلاح کوچکی در کدهای این پروایدر جهت بررسی نال بودن شیءایی که باید dispose شود
در فایل DbConnectionWrapper.cs، متد Dispose را یافته و به نحو زیر اصلاح کنید (بررسی نال نبودن wrappedConnection اضافه شده است):
ج) ساخت یک کلاس پایه Context با قابلیت لاگ فرامین SQL صادره، جهت میسر سازی استفاده مجدد از کدهای آن
د) رفع خطای The given key was not present in the dictionary در حین استفاده از EFTracingProvider
در ادامه کدهای کامل این دو قسمت به همراه یک مثال کاربردی را ملاحظه میکنید:
توضیحات:
تعریف TargetDatabase در Configuration سبب میشود تا خطای The given key was not present in the dictionary در حین استفاده از این پروایدر جدید برطرف شود. به علاوه همانطور که ملاحظه میکنید اطلاعات رشته اتصالی بر اساس قراردادهای توکار EF Code first به نام کلاس Context تنظیم شده است.
کلاس MyLoggedContext، کلاس پایهای است که تنظیمات اصلی «EF Tracing Data Provider» در آن قرار گرفتهاند. برای استفاده از آن باید رشته اتصالی مخصوصی تولید و در اختیار کلاس پایه DbContext قرار گیرد (توسط متد createConnection ذکر شده).
به علاوه در اینجا توسط خاصیت EFTracingProviderConfiguration.LogToFile میتوان نام فایلی را که قرار است عبارات SQL تولیدی در آن درج شوند، ذکر نمود. همچنین یک روش دیگر دستیابی به کلیه عبارات SQL تولیدی را با مقدار دهی CommandExecuting در سازنده کلاس مشاهده میکنید.
اکنون که این کلاس پایه تهیه شده است، تنها کافی است Context معمولی برنامه به نحو زیر تعریف شود:
در ادامه اگر متد RunTests را اجرا کنیم، خروجی ذیل را میتوان در کنسول مشاهده کرد:
قسمتی از این خروجی مرتبط است به متد Seed تعریف شده که تعدادی رکورد را در بانک اطلاعاتی ثبت میکند.
دو select نیز در انتهای کار قابل مشاهده است. اولین مورد به علت فراخوانی متد Any صادر شده است و دیگری به حلقه foreach مرتبط میباشد (چون از AsEnumerable استفاده شده، هربار ارجاع به شیء users، یک رفت و برگشت به بانک اطلاعاتی را سبب خواهد شد. برای رفع این حالت میتوان از متد ToList استفاده کرد.)
در پایان کار، متد update مربوط است به فراخوانی متدهای find و save changes ذکر شده. این خروجی در فایل sql.log نیز در کنار فایل اجرایی برنامه ثبت شده و قابل مشاهده میباشد.
کاربردها
اطلاعات این مثال میتواند پایه نوشتن یک برنامه entity framework profiler باشد.
الف) دریافت کدهای EFTracingProvider اصلی: (+)
از کدهای دریافتی این مجموعه، فقط به دو پوشه EFTracingProvider و EFProviderWrapperToolkit آن نیاز است.
ب) اصلاح کوچکی در کدهای این پروایدر جهت بررسی نال بودن شیءایی که باید dispose شود
در فایل DbConnectionWrapper.cs، متد Dispose را یافته و به نحو زیر اصلاح کنید (بررسی نال نبودن wrappedConnection اضافه شده است):
protected override void Dispose(bool disposing) { if (disposing) { if (this.wrappedConnection != null) this.wrappedConnection.Dispose(); } base.Dispose(disposing); }
ج) ساخت یک کلاس پایه Context با قابلیت لاگ فرامین SQL صادره، جهت میسر سازی استفاده مجدد از کدهای آن
د) رفع خطای The given key was not present in the dictionary در حین استفاده از EFTracingProvider
در ادامه کدهای کامل این دو قسمت به همراه یک مثال کاربردی را ملاحظه میکنید:
using System; using System.Configuration; using System.Data; using System.Data.Common; using System.Data.Entity; using System.Data.Entity.Infrastructure; using System.Data.Entity.Migrations; using System.Diagnostics; using System.Linq; using EFTracingProvider; namespace Sample { public class Person { public int Id { get; set; } public string Name { get; set; } } public class Configuration : DbMigrationsConfiguration<MyContext> { public Configuration() { var className = this.ContextType.FullName; var connectionStringData = ConfigurationManager.ConnectionStrings[className]; if (connectionStringData == null) throw new InvalidOperationException(string.Format("ConnectionStrings[{0}] not found.", className)); TargetDatabase = new DbConnectionInfo(connectionStringData.ConnectionString, connectionStringData.ProviderName); AutomaticMigrationsEnabled = true; AutomaticMigrationDataLossAllowed = true; } protected override void Seed(MyContext context) { for (int i = 0; i < 7; i++) context.Users.Add(new Person { Name = "name " + i }); base.Seed(context); } } public class MyContext : MyLoggedContext { public DbSet<Person> Users { get; set; } } public abstract class MyLoggedContext : DbContext { protected MyLoggedContext() : base(existingConnection: createConnection(), contextOwnsConnection: true) { var ctx = ((IObjectContextAdapter)this).ObjectContext; ctx.GetTracingConnection().CommandExecuting += (s, e) => { Console.WriteLine("{0}\n", e.ToTraceString()); }; } private static DbConnection createConnection() { var st = new StackTrace(); var sf = st.GetFrame(2); // Get the derived class Type in a base class static method var className = sf.GetMethod().DeclaringType.FullName; var connectionStringData = ConfigurationManager.ConnectionStrings[className]; if (connectionStringData == null) throw new InvalidOperationException(string.Format("ConnectionStrings[{0}] not found.", className)); if (!isEFTracingProviderRegistered()) EFTracingProviderConfiguration.RegisterProvider(); EFTracingProviderConfiguration.LogToFile = "log.sql"; var wrapperConnectionString = string.Format(@"wrappedProvider={0};{1}", connectionStringData.ProviderName, connectionStringData.ConnectionString); return new EFTracingConnection { ConnectionString = wrapperConnectionString }; } private static bool isEFTracingProviderRegistered() { var data = (DataSet)ConfigurationManager.GetSection("system.data"); var providerFactories = data.Tables["DbProviderFactories"]; return providerFactories.Rows.Cast<DataRow>() .Select(row => (string)row.ItemArray[1]) .Any(invariantName => invariantName == "EF Tracing Data Provider"); } } public static class Test { public static void RunTests() { Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, Configuration>()); using (var ctx = new MyContext()) { var users = ctx.Users.AsEnumerable(); if (users.Any()) { foreach (var user in users) { Console.WriteLine(user.Name); } } var rnd = new Random(); var user1 = ctx.Users.Find(1); user1.Name = "test user " + rnd.Next(); ctx.SaveChanges(); } } } }
توضیحات:
تعریف TargetDatabase در Configuration سبب میشود تا خطای The given key was not present in the dictionary در حین استفاده از این پروایدر جدید برطرف شود. به علاوه همانطور که ملاحظه میکنید اطلاعات رشته اتصالی بر اساس قراردادهای توکار EF Code first به نام کلاس Context تنظیم شده است.
کلاس MyLoggedContext، کلاس پایهای است که تنظیمات اصلی «EF Tracing Data Provider» در آن قرار گرفتهاند. برای استفاده از آن باید رشته اتصالی مخصوصی تولید و در اختیار کلاس پایه DbContext قرار گیرد (توسط متد createConnection ذکر شده).
به علاوه در اینجا توسط خاصیت EFTracingProviderConfiguration.LogToFile میتوان نام فایلی را که قرار است عبارات SQL تولیدی در آن درج شوند، ذکر نمود. همچنین یک روش دیگر دستیابی به کلیه عبارات SQL تولیدی را با مقدار دهی CommandExecuting در سازنده کلاس مشاهده میکنید.
اکنون که این کلاس پایه تهیه شده است، تنها کافی است Context معمولی برنامه به نحو زیر تعریف شود:
public class MyContext : MyLoggedContext
insert [dbo].[People]([Name]) values (@0) select [Id] from [dbo].[People] where @@ROWCOUNT > 0 and [Id] = scope_identity() -- @0 (dbtype=String, size=-1, direction=Input) = "name 0" insert [dbo].[People]([Name]) values (@0) select [Id] from [dbo].[People] where @@ROWCOUNT > 0 and [Id] = scope_identity() -- @0 (dbtype=String, size=-1, direction=Input) = "name 1" insert [dbo].[People]([Name]) values (@0) select [Id] from [dbo].[People] where @@ROWCOUNT > 0 and [Id] = scope_identity() -- @0 (dbtype=String, size=-1, direction=Input) = "name 2" insert [dbo].[People]([Name]) values (@0) select [Id] from [dbo].[People] where @@ROWCOUNT > 0 and [Id] = scope_identity() -- @0 (dbtype=String, size=-1, direction=Input) = "name 3" insert [dbo].[People]([Name]) values (@0) select [Id] from [dbo].[People] where @@ROWCOUNT > 0 and [Id] = scope_identity() -- @0 (dbtype=String, size=-1, direction=Input) = "name 4" insert [dbo].[People]([Name]) values (@0) select [Id] from [dbo].[People] where @@ROWCOUNT > 0 and [Id] = scope_identity() -- @0 (dbtype=String, size=-1, direction=Input) = "name 5" insert [dbo].[People]([Name]) values (@0) select [Id] from [dbo].[People] where @@ROWCOUNT > 0 and [Id] = scope_identity() -- @0 (dbtype=String, size=-1, direction=Input) = "name 6" SELECT [Extent1].[Id] AS [Id], [Extent1].[Name] AS [Name] FROM [dbo].[People] AS [Extent1] SELECT [Extent1].[Id] AS [Id], [Extent1].[Name] AS [Name] FROM [dbo].[People] AS [Extent1] name 0 name 1 name 2 name 3 name 4 name 5 name 6 update [dbo].[People] set [Name] = @0 where ([Id] = @1) -- @0 (dbtype=String, size=-1, direction=Input) = "test user 1355460609" -- @1 (dbtype=Int32, size=0, direction=Input) = 1
قسمتی از این خروجی مرتبط است به متد Seed تعریف شده که تعدادی رکورد را در بانک اطلاعاتی ثبت میکند.
دو select نیز در انتهای کار قابل مشاهده است. اولین مورد به علت فراخوانی متد Any صادر شده است و دیگری به حلقه foreach مرتبط میباشد (چون از AsEnumerable استفاده شده، هربار ارجاع به شیء users، یک رفت و برگشت به بانک اطلاعاتی را سبب خواهد شد. برای رفع این حالت میتوان از متد ToList استفاده کرد.)
در پایان کار، متد update مربوط است به فراخوانی متدهای find و save changes ذکر شده. این خروجی در فایل sql.log نیز در کنار فایل اجرایی برنامه ثبت شده و قابل مشاهده میباشد.
کاربردها
اطلاعات این مثال میتواند پایه نوشتن یک برنامه entity framework profiler باشد.
اشتراکها
مقایسه React و Angular 4
When you start working on a new web application you will probably need to analyze different tools to deal with the different functionalities that you have to work on. As soon as you start searching for alternatives you are going to run across Angular and React, they are without any doubt two of the major options to consider, at least till today.
اشتراکها