اشتراکها
مطالب دورهها
کوئری نویسی مقدماتی در RavenDB
با شروع کوئری نویسی مقدماتی در RavenDB، در قسمت اول این مباحث، توسط فراخوانی متد Load یک سشن، آشنا شدید. در ادامه مباحث تکمیلی آنرا مرور خواهیم کرد.
امکان استفاده از LINQ در RavenDB
RavenDB از LINQ جهت کوئری نویسی پشتیبانی میکند. برای استفاده از آن، در ادامه مطلب اول، ابتدا سرور RavenDB را اجرا نموده و سپس برنامه کنسول را به نحو ذیل تغییر دهید:
در RavenDB برای دسترسی به امکانات LINQ، کار با متد Query یک سشن آغاز میشود و پس از آن، امکان استفاده از متدهای متداول LINQ مانند مثال فوق وجود خواهد داشت. البته بدیهی است مباحثی مانند JOIN و امثال آن در یک بانک اطلاعاتی NoSQL پشتیبانی نمیشود. ضمنا باید درنظر داشت که مبحث safe by default در اینجا نیز اعمال میشود. برای مثال اگر به کنسول سرور RavenDB که در حال اجرا است مراجعه کنید، یک چنین خروجی را حین اجرای مثال فوق میتوان مشاهده کرد که در آن pageSize پیش فرضی اعمال شده است:
یعنی در عمل کوئریرا که اجرا کرده است، شبیه به کوئری ذیل میباشد و یک Take پیش فرض بر روی آن اعمال شده است:
علت این مساله نیز به تصمیم نویسنده اصلی آن بر میگردد؛ ایشان پیش از شروع به تهیه RavenDB، کار تهیه انواع و اقسام پروفایلرهای مهم ORMهای معروف مانند NHibernate و Entity framework را انجام داده است و در این حین، یکی از مهمترین مشکلاتی را که با آنها در کدهای متداول برنامه نویسها یافته است، unbounded queries است. کوئریهایی که حد و مرزی برای بازگشت اطلاعات قائل نمیشوند. داشتن این نوع کوئریها با تعداد بالای کاربر، یعنی مصرف بیش از حد RAM بر روی سرور، به همراه بار پردازشی بیش از حد و غیر ضروری. چون عملا حتی اگر 10 هزار رکورد بازگشت داده شوند، عموم برنامه نویسها حداکثر 100 رکورد آنرا در یک صفحه نمایش میدهند و نه تمام رکوردها را.
ارتباط Lucene.NET و RavenDB
کل LINQ API تهیه شده در RavenDB یک محصور کننده امکانات Lucene.NET است. اگر پیشتر با Lucene.NET کار کرده باشید، در خروجی حالت دیباگ کنسول سرور فوق، سطر «Query: Title:Raven*» آشنا به نظر خواهد رسید. دقیقا کوئری LINQ نوشته شده به یک کوئری با Syntax مخصوص Lucene.NET ترجمه شدهاست. برای نمونه اگر علاقمند باشید که مستقیما کوئریهای خاص لوسین را در RavenDB اجرا کنید، از Syntax ذیل میتوان استفاده کرد:
و یا اگر علاقمند به حفظ کردن Syntax خاص لوسین نیستید، یک سری متد الحاقی خاص نیز در اینجا برای LuceneQuery تدارک دیده شده است. برای مثال کوئری رشتهای فوق، معادل کوئری strongly typed ذیل است:
استفاده مجدد از کوئریها در RavenDB
در RavenDB، متد Query به صورت immutable تعریف شده است و متد LuceneQuery حالت mutable دارد (ترکیبات آن نیز یک وهله است).
یک مثال:
در اینجا از کوئری ابتدایی، در دو کوئری مجزا استفاده مجدد شده است. ترجمه خروجی سه کوئری فوق به نحو زیر است:
به این معنا که زمانیکه به eyeQuery رسیدیم، نتیجه ageQuery با آن ترکیب نمیشود؛ چون متد Query از نوع immutable است.
در ادامه اگر همین سه کوئری فوق را با فرمت LuceneQuery تهیه کنیم، به عبارات ذیل خواهیم رسید:
در خروجیهای این سه کوئری، مورد سوم مهم است:
همانطور که مشاهده میکنید، کوئری سوم، عبارت کوئری دوم را نیز به همراه دارد؛ این مورد دقیقا مفهوم اشیاء mutable یا تک وهلهای است مانند LuceneQuery در اینجا.
And و Or شدن کوئریهای ترکیبی در RavenDB
در مثال استفاده مجدد از کوئریها، زمانیکه از Where استفاده شد، بین عبارات حاصل AND قرار گرفته است. این مورد را به نحو ذیل میتوان تنظیم کرد و مثلا به OR تغییر داد:
صفحه بندی اطلاعات در RavenDB
در ابتدای بحث عنوان شد که کوئری LINQ اجرا شده در RavenDB، یک Take مخفی و پیش فرض تنظیم شده به 128 آیتم را دارد. اکنون سؤال این خواهد بود که چگونه میتوان اطلاعات را به صورت صفحه بندی شده، بر اساس شماره صفحه خاصی نمایش داد.
برای انجام صفحه بندی در RavenDB، کافی است از متدهای Skip و Take بر اساس محاسباتی که مشاهده میکنید، استفاده گردد.
دریافت اطلاعات آماری کوئری اجرا شده
در RavenDB امکان دریافت یک سری اطلاعات آماری از کوئری اجرا شده نیز وجود دارد؛ برای مثال یک کوئری چند ثانیه طول کشیده است، چه تعدادی رکورد را بازگشت داده است و امثال آن. برای پیاده سازی آن، نیاز است از متد الحاقی Statistics به نحو ذیل استفاده کرد:
متد الحاقی Statistics پس از متد Query که نقطه آغازین نوشتن کوئریهای LINQ است، فراخوانی شده و یک پارامتر out از نوع RavenQueryStatistics تعریف شده در فضای نام Raven.Client را دریافت میکند. پس از پایان کوئری میتوان از این خروجی جهت نمایش اطلاعات آماری کوئری استفاده کرد.
امکانات ویژه فضای نام Raven.Client.Linq
یک سری متد الحاقی خاص جهت تهیه سادهتر کوئریهای LINQ در فضای نام Raven.Client.Linq قرار دارند که پس از تعریف آن قابل دسترسی خواهند بود:
برای مثال در اینجا متد الحاقی جدید In را مشاهده میکنید که شبیه به کوئری SQL ذیل در دنیای بانکهای اطلاعاتی رابطهای عمل میکند:
اتصال به RavenDB با استفاده از برنامه معروف LINQPad
اگر علاقمند باشید که کوئریهای خود را در محیط برنامه معروف LINQPad نیز آزمایش کنید، درایور مخصوص RavenDB آنرا از آدرس ذیل میتوانید دریافت نمائید:
امکان استفاده از LINQ در RavenDB
RavenDB از LINQ جهت کوئری نویسی پشتیبانی میکند. برای استفاده از آن، در ادامه مطلب اول، ابتدا سرور RavenDB را اجرا نموده و سپس برنامه کنسول را به نحو ذیل تغییر دهید:
using System; using System.Linq; using Raven.Client.Document; using RavenDBSample01.Models; namespace RavenDBSample01 { class Program { static void Main(string[] args) { using (var store = new DocumentStore { Url = "http://localhost:8080" }.Initialize()) { using (var session = store.OpenSession()) { var questions = session.Query<Question>().Where(x => x.Title.StartsWith("Raven")); foreach (var question in questions) { Console.WriteLine(question.Title); } } } } } }
Available commands: cls, reset, gc, q Request # 1: GET - 179 ms - <system> - 404 - /docs/Raven/Replication/Destinations Request # 2: GET - 3,818 ms - <system> - 200 - /indexes/dynamic/Questions?&query=Title%3ARaven*&pageSize=128 Query: Title:Raven* Time: 3,494 ms Index: Auto/Questions/ByTitle Results: 2 returned out of 2 total.
var questions = session.Query<Question>().Where(x => x.Title.StartsWith("Raven")).Take(128);
ارتباط Lucene.NET و RavenDB
کل LINQ API تهیه شده در RavenDB یک محصور کننده امکانات Lucene.NET است. اگر پیشتر با Lucene.NET کار کرده باشید، در خروجی حالت دیباگ کنسول سرور فوق، سطر «Query: Title:Raven*» آشنا به نظر خواهد رسید. دقیقا کوئری LINQ نوشته شده به یک کوئری با Syntax مخصوص Lucene.NET ترجمه شدهاست. برای نمونه اگر علاقمند باشید که مستقیما کوئریهای خاص لوسین را در RavenDB اجرا کنید، از Syntax ذیل میتوان استفاده کرد:
var questions = session.Advanced.LuceneQuery<Question>().Where("Title:Raven*").ToList();
var questions = session.Advanced.LuceneQuery<Question>().WhereStartsWith(x => x.Title, "Raven").ToList();
استفاده مجدد از کوئریها در RavenDB
در RavenDB، متد Query به صورت immutable تعریف شده است و متد LuceneQuery حالت mutable دارد (ترکیبات آن نیز یک وهله است).
یک مثال:
var query = session.Query<User>().Where(x => x.Name.StartsWith("A")); var ageQuery = query.Where(x => x.Age > 21); var eyeQuery = query.Where(x => x.EyeColor == "blue");
query - Name:A* ageQuery - (Name:A*) AND (Age_Range:{Ix21 TO NULL}) eyeQuery - (Name:A*) AND (EyeColor:blue)
در ادامه اگر همین سه کوئری فوق را با فرمت LuceneQuery تهیه کنیم، به عبارات ذیل خواهیم رسید:
var luceneQuery = session.Advanced.LuceneQuery<User>().WhereStartsWith(x => x.Name, "A"); var ageLuceneQuery = luceneQuery.WhereGreaterThan(x => x.Age, 21); var eyeLuceneQuery = luceneQuery.WhereEquals(x => x.EyeColor, "blue");
luceneQuery - Name:A* ageLuceneQuery - Name:A* Age_Range:{Ix21 TO NULL} eyeLuceneQuery - Name:A* Age_Range:{Ix21 TO NULL} EyeColor:blue
And و Or شدن کوئریهای ترکیبی در RavenDB
در مثال استفاده مجدد از کوئریها، زمانیکه از Where استفاده شد، بین عبارات حاصل AND قرار گرفته است. این مورد را به نحو ذیل میتوان تنظیم کرد و مثلا به OR تغییر داد:
session.Advanced.LuceneQuery<User>().UsingDefaultOperator(QueryOperator.And);
صفحه بندی اطلاعات در RavenDB
در ابتدای بحث عنوان شد که کوئری LINQ اجرا شده در RavenDB، یک Take مخفی و پیش فرض تنظیم شده به 128 آیتم را دارد. اکنون سؤال این خواهد بود که چگونه میتوان اطلاعات را به صورت صفحه بندی شده، بر اساس شماره صفحه خاصی نمایش داد.
using System; using System.Linq; using Raven.Client.Document; using RavenDBSample01.Models; namespace RavenDBSample01 { class Program { static void Main(string[] args) { using (var store = new DocumentStore { Url = "http://localhost:8080" }.Initialize()) { using (var session = store.OpenSession()) { int pageNumber = 0; int resultsPerPage = 2; var questions = session.Query<Question>() .Where(x => x.Title.StartsWith("Raven")) .Skip(pageNumber * resultsPerPage) .Take(resultsPerPage); foreach (var question in questions) { Console.WriteLine(question.Title); } } } } } }
دریافت اطلاعات آماری کوئری اجرا شده
در RavenDB امکان دریافت یک سری اطلاعات آماری از کوئری اجرا شده نیز وجود دارد؛ برای مثال یک کوئری چند ثانیه طول کشیده است، چه تعدادی رکورد را بازگشت داده است و امثال آن. برای پیاده سازی آن، نیاز است از متد الحاقی Statistics به نحو ذیل استفاده کرد:
using System; using System.Linq; using Raven.Client.Document; using RavenDBSample01.Models; using Raven.Client; namespace RavenDBSample01 { class Program { static void Main(string[] args) { using (var store = new DocumentStore { Url = "http://localhost:8080" }.Initialize()) { using (var session = store.OpenSession()) { int pageNumber = 0; int resultsPerPage = 2; RavenQueryStatistics stats; var questions = session.Query<Question>() .Statistics(out stats) .Where(x => x.Title.StartsWith("Raven")) .Skip(pageNumber * resultsPerPage) .Take(resultsPerPage); foreach (var question in questions) { Console.WriteLine(question.Title); } Console.WriteLine("TotalResults: {0}", stats.TotalResults); } } } } }
امکانات ویژه فضای نام Raven.Client.Linq
یک سری متد الحاقی خاص جهت تهیه سادهتر کوئریهای LINQ در فضای نام Raven.Client.Linq قرار دارند که پس از تعریف آن قابل دسترسی خواهند بود:
var list = session.Query<Question>().Where(q => q.By.In<string>(arrayOfUsers))).ToArray()
SELECT * FROM tbl WHERE data IN (1, 2, 3)
اتصال به RavenDB با استفاده از برنامه معروف LINQPad
اگر علاقمند باشید که کوئریهای خود را در محیط برنامه معروف LINQPad نیز آزمایش کنید، درایور مخصوص RavenDB آنرا از آدرس ذیل میتوانید دریافت نمائید:
اشتراکها
اعتبارسنجی JSON با JSON-Schema
When you’re dealing with complex and structured data, you need to determine whether the data is valid or not. JSON-Schema is the standard of JSON documents that describes the structure and the requirements of your JSON data. In this two-part series, you’ll learn how to use JSON-Schema to validate data.
نظرات مطالب
مراحل تنظیم Let's Encrypt در IIS
یک نکتهی تکمیلی
ACME V1 تا چند ماه دیگر به پایان خواهد رسید:In June of 2020 we will stop allowing new domains to validate via ACMEv1.
یک نمونه لاگ اجرای نگارش جدید آن به صورت زیر است:
A simple Windows ACMEv2 client (WACS) Software version 2.1.3.671 (RELEASE, PLUGGABLE) IIS version 7.5 Running with administrator credentials Scheduled task not configured yet Please report issues at https://github.com/PKISharp/win-acme N: Create new certificate (simple for IIS) M: Create new certificate (full options) L: List scheduled renewals R: Renew scheduled S: Renew specific A: Renew *all* O: More options... Q: Quit Please choose from the menu: m Running in mode: Interactive, Advanced Please specify how the list of domain names that will be included in the certificate should be determined. If you choose for one of the "all bindings" options, the list will automatically be updated for future renewals to reflect the bindings at that time. 1: IIS 2: Manual input 3: CSR created by another program C: Abort How shall we determine the domain(s) to include in the certificate?: 1 Please select which website(s) should be scanned for host names. You may input one or more site identifiers (comma separated) to filter by those sites, or alternatively leave the input empty to scan *all* websites. 1: Default Web Site (2 bindings) Site identifier(s) or <ENTER> to choose all: 1 1: dotnettips.info (Site 1) 2: www.dotnettips.info (Site 1) You may either choose to include all listed bindings as host names in your certificate, or apply an additional filter. Different types of filters are available. 1: Pick specific bindings from the list 2: Pick bindings based on a search pattern 3: Pick bindings based on a regular expression 4: Pick *all* bindings How do you want to pick the bindings?: 4 1: dotnettips.info (Site 1) 2: www.dotnettips.info (Site 1) Please pick the most important host name from the list. This will be displayed to your users as the subject of the certificate. Common name: 2 1: dotnettips.info (Site 1) 2: www.dotnettips.info (Site 1) Continue with this selection? (y*/n) - yes Target generated using plugin IIS: www.dotnettips.info and 1 alternatives Suggested friendly name '[IIS] Default Web Site, (any host)', press <ENTER> to accept or type an alternative: <Enter> The ACME server will need to verify that you are the owner of the domain names that you are requesting the certificate for. This happens both during initial setup *and* for every future renewal. There are two main methods of doing so: answering specific http requests (http-01) or create specific dns records (dns-01). For wildcard domains the latter is the only option. Various additional plugins are available from https://github.com/PKISharp/win-acme/. 1: [http-01] Save verification files on (network) path 2: [http-01] Serve verification files from memory (recommended) 3: [http-01] Upload verification files via FTP(S) 4: [http-01] Upload verification files via SSH-FTP 5: [http-01] Upload verification files via WebDav 6: [dns-01] Create verification records manually (auto-renew not possible) 7: [dns-01] Create verification records with acme-dns (https://github.com/joohoi/acme-dns) 8: [dns-01] Create verification records with your own script 9: [tls-alpn-01] Answer TLS verification request from win-acme C: Abort How would you like prove ownership for the domain(s) in the certificate?: 2 After ownership of the domain(s) has been proven, we will create a Certificate Signing Request (CSR) to obtain the actual certificate. The CSR determines properties of the certificate like which (type of) key to use. If you are not sure what to pick here, RSA is the safe default. 1: Elliptic Curve key 2: RSA key What kind of private key should be used for the certificate?: 2 When we have the certificate, you can store in one or more ways to make it accessible to your applications. The Windows Certificate Store is the default location for IIS (unless you are managing a cluster of them). 1: IIS Central Certificate Store (.pfx per domain) 2: PEM encoded files (Apache, nginx, etc.) 3: Windows Certificate Store C: Abort How would you like to store the certificate?: 3 1: IIS Central Certificate Store (.pfx per domain) 2: PEM encoded files (Apache, nginx, etc.) 3: No additional storage steps required C: Abort Would you like to store it in another way too?: 3 With the certificate saved to the store(s) of your choice, you may choose one or more steps to update your applications, e.g. to configure the new thumbprint, or to update bindings. 1: Create or update https bindings in IIS 2: Create or update ftps bindings in IIS 3: Start external script or program 4: Do not run any (extra) installation steps Which installation step should run first?: 1 Use different site for installation? (y/n*) - no 1: Create or update ftps bindings in IIS 2: Start external script or program 3: Do not run any (extra) installation steps Add another installation step?: 3 Enter email(s) for notifications about problems and abuse (comma seperated): name@site.com Terms of service: C:\ProgramData\win-acme\acme-v02.api.letsencrypt.org\LE-SA-v1.2-November-15-2017.pdf Open in default application? (y/n*) - no Do you agree with the terms? (y*/n) - yes Authorize identifier: dotnettips.info Authorizing dotnettips.info using http-01 validation (SelfHosting) Authorization result: valid Authorize identifier: www.dotnettips.info Authorizing www.dotnettips.info using http-01 validation (SelfHosting) Authorization result: valid Requesting certificate [IIS] Default Web Site, (any host) Store with CertificateStore... Installing certificate in the certificate store Adding certificate [IIS] Default Web Site, (any host) @ 2020/2/1 9:43:55 to store My Installing with IIS... Updating existing https binding www.dotnettips.info:443 (flags: 0) Updating existing https binding dotnettips.info:443 (flags: 0) Committing 2 https binding changes to IIS Adding Task Scheduler entry with the following settings - Name win-acme renew (acme-v02.api.letsencrypt.org) - Path C:\Programs\win-acme.v2.1.3.671.x64.pluggable - Command wacs.exe --renew --baseuri "https://acme-v02.api.letsencrypt.org/" - Start at 09:00:00 - Time limit 02:00:00 Do you want to specify the user the task will run as? (y/n*) - no
- روش دوم بررسی علت وقوع internal server error نصب ELMAH هست. این افزونه علت واقعی استثنای رخ داده را به همراه stack trace کامل، برای شما ذخیره میکند.
نصاب سریع آن برای ASP.NET MVC
مقالات مرتبط با آن در سایت
- روش سوم آن، مراجعه به لاگهای ویندوز است: Computer management -> Event viewer
نصاب سریع آن برای ASP.NET MVC
مقالات مرتبط با آن در سایت
- روش سوم آن، مراجعه به لاگهای ویندوز است: Computer management -> Event viewer
وبلاگها ، سایتها و مقالات ایرانی (داخل و خارج از ایران)
- بهبود در توابع Table-Valued
- ظاهر جدید برای ویژوال استودیو 2010
- سورس نرم افزار اشتراک
- فریم ورک های سی اس اس را بهتر بشناسیم
- غزال مایکروسافت در راه است
- بررسی سایت ماهواره امید
- مروری بر سافاری 4
- صدا زدن یک Web service از طریق jquery
- نصب OTRS روی ویندوز ویستا
- آموزش کامل اسکریپت نویسی nsis - ساخت برنامه نصب
- توضیحی اجمالی در مورد singleton pattern
- MySQL Storage Engines
- مشکل بهم ریختگی متون فارسی انگلیسی در کامپیوتر
- ۴۸ نکته و اصل مهم در برنامه نویسی پی اچ پی
- فشرده سازی صفحات در ASP.net
امنیت
Visual Studio
ASP. Net
طراحی و توسعه وب
- ورود به دنیای jQuery plugins
- لیستی از 240 افزونهی جیکوئری
- و همچنین 20 مورد دیگر
- معرفی 13 screengrab webservices
- jQuery Chart Plugins
- برگههای تقلب وبی!
- خودتان را برای IE8 آماده کنید!
PHP
اسکیوال سرور
سی شارپ
عمومی دات نت
- Maestro ، زبان جدید دات نتی برای برنامه نویسی موازی
- چگونه تشخیص دهیم که یک اسمبلی دات نت به چه زبانی نوشته شده است؟
- ADO.NET Data Services v1.5 CTP1
ویندوز
مسایل اجتماعی و انسانی برنامه نویسی
متفرقه
نرم افزارهای Windows 7, Windows Server 2008 R2 and SQL Server 2008 SP2 32 & 64 bit Enterprise Edition موفق به کسب گواهینامه امنیتی Common Criteria شدند. کسب این مجوز امنیتی یکی از شروط اصلی و اجباری استفاده از یک نرم افزار در وزارت دفاع آمریکا است.
این بررسیها زیر نظر وزارت دفاع و آژانس امنیت ملی آمریکا و همچنین آلمان برگزار شده و گزارشهای مرتبط با ویندوز 7 و SQL Server 2008 را از اینجا میتوانید دریافت کنید: (+) و (+)
ماخذ: (+)
مطالب مشابه:
امنیت SQL Server 2008
مقایسه امنیتی نگارشهای مختلف ویندوز
بر اساس رفتار پیش فرض در دیتابیس SQL Server، در زمان انجام دادن یک دستور که منجر به ایجاد تغییرات در اطلاعات موجود در جدول میشود (برای مثال دستور Update)، جدول مربوطه به صورت کامل Lock میشود، ولو آن دستور Update، فقط با یکی از رکوردهای آن جدول کار داشته باشد.
داریم
در سیستمهای با تعداد تراکنش بالا و دارای تعداد زیاد کلاینت، این رفتار پیش فرض موجب ایجاد صفی از تراکنشهای در حال انتظار بر روی جداولی میشود که ویرایشهای زیادی بر روی آنها رخ میدهد.
اگر چه که بنظر این مشکل راه حلهای زیادی دارد، لکن آن راه حلی که همیشه موثر عمل میکند استفاده از SQL Server Table Hints است.
SQL Server Table Hints به تمامی آن دستوراتی گفته میشود که هنگام اجرای دستور اصلی (برای مثال Select و یا Update) رفتار پیش فرض SQL Server را بر اساس Hint ارائه شده تغییر میدهند.
لیست کامل این Hintها را میتوانید در اینجا مشاهده کنید.
Hint ای که در اینجا برای ما مفید است، آن است که به SQL Server بگوییم هنگام اجرای دستور Update، به جای Lock کردن کل جدول، فقط رکورد در حال ویرایش را Lock کند، و این باعث میشود تا باقی تراکنش ها، که ای بسا با سایر رکوردهای آن جدول کار داشته باشند متوقف نشوند، که البته این مسئله کمی به افزایش مصرف حافظه میانجامد، لکن مقدار افزایش بسیار ناچیز است.
این Hint که rowlock نام دارد در تراکنشهای با Isolation Level تنظیم شده بر روی Snapshot باید با یک Table Hint دیگر با نام updlock ترکیب شود.
توضیحات مفصلتر این دو Hint در لینک مربوطه آمده است.
بنابر این، بجای دستور
update products set Name = "Test" Where Id = 1
update products with (nolock,updlock) set Name = "Test" where Id = 1
تا اینجا مشکل خاصی وجود ندارد، آنچه که از اینجا به بعد اهمیت دارد این است که در هنگام کار با Entity Framework، اساسا ما نویسنده دستورات Update نیستیم که به آنها Hint اضافه کنیم یا نه، بلکه دستورات SQL بوسیله Entity Framework ایجاد میشوند.
در Entity Framework، مکانیزمی تعبیه شده است با نام Db Command Interceptor که به شما اجازه میدهد دستورات SQL ساخته شده را Log کنید و یا قبل از اجرا تغییر دهید، که برای اضافه نمودن Table Hintها ما از این روش استفاده میکنیم، برای انجام این کار داریم: (توضیحات در ادامه)
public class UpdateRowLockHintDbCommandInterceptor : IDbCommandInterceptor { public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<Int32> interceptionContext) { if (command.CommandType != CommandType.Text) return; // (1) if (!(command is SqlCommand)) return; // (2) SqlCommand sqlCommand = (SqlCommand)command; String commandText = sqlCommand.CommandText; String updateCommandRegularExpression = "(update) "; Boolean isUpdateCommand = Regex.IsMatch(commandText, updateCommandRegularExpression, RegexOptions.IgnoreCase | RegexOptions.Multiline); // You may use better regular expression pattern here. if (isUpdateCommand) { Boolean isSnapshotIsolationTransaction = sqlCommand.Transaction != null && sqlCommand.Transaction.IsolationLevel == IsolationLevel.Snapshot; String tableHintToAdd = isSnapshotIsolationTransaction ? " with (rowlock , updlock) set " : " with (rowlock) set "; commandText = Regex.Replace(commandText, "^(set) ", (match) => { return tableHintToAdd; }, RegexOptions.IgnoreCase | RegexOptions.Multiline); command.CommandText = commandText; } }
این کد در قسمت (1) ابتدا تشخیص میدهد که آیا این یک Command دارای Command Text است یا خیر، برای مثال اگر فراخوانی یک Stored Procedure است، ما با آن کاری نداریم.
در قسمت دوم تشخیص میدهیم که آیا با SQL Server در حال تعامل هستیم، یا برای مثال با Oracle و ...، که ما برای Table Hintها فقط با SQL Server کار داریم.
سپس باید تشخیص دهیم که آیا این یک دستور update است یا خیر ؟ برای این منظور از Regular Expressionها استفاده کرده ایم، که خیلی به بحث آموزش این پست مربوط نیست، به صورت کلی از Regular Expressionها برای یافتن و بررسی و جایگزینی عبارات با قاعده در هنگام کار با رشتهها استفاده میشود.
ممکن است Regular Expression ای که شما مینویسید بسیار بهتر از این نمونه باشد، که در این صورت خوشحال میشوم در قسمت نظرات آنرا قرار دهید.
در نهایت با بررسی Transaction Isolation Level مربوطه که Snapshot است یا خیر، به درج یک یا هر دو Table Hint مربوطه اقدام مینماییم.