$("#id1").change(function () { // trigger RemoteValidation $('#id1').removeData('previousValue'); //clear cache $('form').validate().element('#id1'); //retrigger remote call // $('#id1').blur(); });
نام این جدول را با درنظر گرفتن شرایط موجود میتوان Resources گذاشت.
ستون Name برای ذخیره نام منبع درنظر گرفته شده است. این نام برابر نام منابع درخواستی در سیستم مدیریت منابع ASP.NET است که درواقع برابر همان نام فایل منبع اما بدون پسوند resx. است.
ستون Key برای نگهداری کلید ورودی منبع استفاده میشود که دقیقا برابر همان مقداری است که درون فایلهای resx. ذخیره میشود.
ستون Culture برای ذخیره کالچر ورودی منبع به کار میرود. این مقدار میتواند برای کالچر پیشفرض برنامه برابر رشته خالی باشد.
ستون Value نیز برای نگهداری مقدار ورودی منبع استفاده میشود.
برای ستون Id میتوان از GUID نیز استفاده کرد. در اینجا برای راحتی کار از نوع داده bigint و خاصیت Identity برای تولید خودکار آن در Sql Server استفاده شده است.
نکته: برای امنیت بیشتر میتوان یک Unique Constraint بر روی سه فیلد Name و Key و Culture اعمال کرد.
برای نمونه به تصویر زیر که ذخیره تعدای ورودی منبع را درون جدول Resources نمایش میدهد دقت کنید:
اصلاح کلاس DbResourceProviderFactory
برای ذخیره منابع محلی، جهت اطمینان از یکسان بودن نام منبع، متد مربوطه در کلاس DbResourceProviderFactory باید بهصورت زیر تغییر کند:
public override IResourceProvider CreateLocalResourceProvider(string virtualPath) { if (!string.IsNullOrEmpty(virtualPath)) { virtualPath = virtualPath.Remove(0, virtualPath.IndexOf('/') + 1); // removes everything from start to the first '/' } return new LocalDbResourceProvider(virtualPath); }
ارتباط با دیتابیس
خوشبختانه برای تبادل اطلاعات با جدول بالا امروزه راههای زیادی وجود دارد. برای پیادهسازی آن مثلا میتوان از یک اینترفیس استفاده کرد. سپس با استفاده از سازوکارهای موجود مثلا بهکارگیری IoC، نمونه مناسبی از پیادهسازی اینترفیس مذبور را در اختیار برنامه قرار داد.
اما برای جلوگیری از پیچیدگی بیش از حد و دور شدن از مبحث اصلی، برای پیادهسازی فعلی از EF Code First به صورت مستقیم در پروژه استفاده شده است که سری آموزشی کاملی از آن در همین سایت وجود دارد.
پس از پیادهسازی کلاسهای مرتبط برای استفاده از EF Code First، از کلاس ResourceData که در بخش اول نیز نشان داده شده بود، برای کپسوله کردن ارتباط با دادهها استفاده میشود که نمونهای ابتدایی از آن در زیر آورده شده است:
using System.Collections.Generic; using System.Linq; using DbResourceProvider.Models; namespace DbResourceProvider.Data { public class ResourceData { private readonly string _resourceName; public ResourceData(string resourceName) { _resourceName = resourceName; } public Resource GetResource(string resourceKey, string culture) { using (var data = new TestContext()) { return data.Resources.SingleOrDefault(r => r.Name == _resourceName && r.Key == resourceKey && r.Culture == culture); } } public List<Resource> GetResources(string culture) { using (var data = new TestContext()) { return data.Resources.Where(r => r.Name == _resourceName && r.Culture == culture).ToList(); } } } }
using System.Collections.Generic; using System.Globalization; using DbResourceProvider.Data; namespace DbResourceProvider { public class DbResourceManager { private readonly string _resourceName; private readonly Dictionary<string, Dictionary<string, object>> _resourceCacheByCulture; public DbResourceManager(string resourceName) { _resourceName = resourceName; _resourceCacheByCulture = new Dictionary<string, Dictionary<string, object>>(); } public object GetObject(string resourceKey, CultureInfo culture) { return GetCachedObject(resourceKey, culture.Name); } private object GetCachedObject(string resourceKey, string cultureName) { if (!_resourceCacheByCulture.ContainsKey(cultureName)) _resourceCacheByCulture.Add(cultureName, new Dictionary<string, object>()); var cachedResource = _resourceCacheByCulture[cultureName]; lock (this) { if (!cachedResource.ContainsKey(resourceKey)) { var data = new ResourceData(_resourceName); var dbResource = data.GetResource(resourceKey, cultureName); if (dbResource == null) return null; var cachedResources = _resourceCacheByCulture[cultureName]; cachedResources.Add(dbResource.Key, dbResource.Value); } } return cachedResource[resourceKey]; } } }
private object GetCachedObject(string resourceKey, string cultureName) { lock (this) { if (!_resourceCacheByCulture.ContainsKey(cultureName)) { _resourceCacheByCulture.Add(cultureName, new Dictionary<string, object>()); var cachedResources = _resourceCacheByCulture[cultureName]; var data = new ResourceData(_resourceName); var dbResources = data.GetResources(cultureName); foreach (var dbResource in dbResources) { cachedResources.Add(dbResource.Key, dbResource.Value); } } } var cachedResource = _resourceCacheByCulture[cultureName]; return !cachedResource.ContainsKey(resourceKey) ? null : cachedResource[resourceKey]; }
using System.Collections; using System.Collections.Generic; using System.Globalization; namespace DbResourceProvider { public class CultureFallbackProvider : IEnumerable<CultureInfo> { private readonly CultureInfo _startingCulture; private readonly CultureInfo _neutralCulture; private readonly bool _tryParentCulture; public CultureFallbackProvider(CultureInfo startingCulture = null, CultureInfo neutralCulture = null, bool tryParentCulture = true) { _startingCulture = startingCulture ?? CultureInfo.CurrentUICulture; _neutralCulture = neutralCulture; _tryParentCulture = tryParentCulture; } #region Implementation of IEnumerable<CultureInfo> public IEnumerator<CultureInfo> GetEnumerator() { var reachedNeutralCulture = false; var currentCulture = _startingCulture; do { if (_neutralCulture != null && currentCulture.Name == _neutralCulture.Name) { yield return CultureInfo.InvariantCulture; reachedNeutralCulture = true; break; } yield return currentCulture; currentCulture = currentCulture.Parent; } while (_tryParentCulture && !HasInvariantCultureName(currentCulture)); if (!_tryParentCulture || HasInvariantCultureName(_startingCulture) || reachedNeutralCulture) yield break; yield return CultureInfo.InvariantCulture; } #endregion #region Implementation of IEnumerable IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion private bool HasInvariantCultureName(CultureInfo culture) { return culture.Name == CultureInfo.InvariantCulture.Name; } } }
public object GetObject(string resourceKey, CultureInfo culture) { foreach (var currentCulture in new CultureFallbackProvider(culture)) { var value = GetCachedObject(resourceKey, currentCulture.Name); if (value != null) return value; } throw new KeyNotFoundException("The specified 'resourceKey' not found."); }
ابتدا تنظیمات موردنیاز فایل کانفیگ را که در قسمت قبل نشان داده شد، در برنامه خود اعمال کنید.
دادههای نمونه نشان داده شده در ابتدای این مطلب را درنظر بگیرید. حال اگر در یک برنامه وب اپلیکیشن، صفحه Default.aspx در ریشه سایت حاوی دو کنترل زیر باشد:
<asp:Label ID="Label1" runat="server" meta:resourcekey="Label1" /> <asp:Label ID="Label2" runat="server" meta:resourcekey="Label2" />
سپس تغییر زیر را در فایل web.config اعمال کنید تا کالچر UI سایت به fa تغییر یابد (به بخش "uiCulture="fa دقت کنید):
<globalization uiCulture="fa" resourceProviderFactoryType = "DbResourceProvider.DbResourceProviderFactory, DbResourceProvider" />
میبینید که با توجه به عدم وجود مقداری برای Label2.Text برای کالچر fa، عملیات fallback اتفاق افتاده است.
کار تولید یک پرووایدر منابع سفارشی دیتابیسی به اتمام رسید. تا اینجا اصول کلی تولید یک پرووایدر سفارشی شرح داده شد. بدین ترتیب میتوان برای هر حالت خاص دیگری نیز پرووایدرهای سفارشی مخصوص ساخت تا مدیریت منابع به آسانی تحت کنترل برنامه نویس قرار گیرد.
اما نکتهای را که باید به آن توجه کنید این است که در پیادهسازیهای نشان داده شده با توجه به نحوه کششدن مقادیر ورودیها، اگر این مقادیر در دیتابیس تغییر کنند، تا زمانیکه سایت ریست نشود این تغییرات در برنامه اعمال نخواهد شد. زیرا همانطور که اشاره شد، مدیریت نمونههای تولیدشده از پرووایدرهای منابع برای هر منبع درخواستی درنهایت برعهده ASP.NET است. بنابراین باید مکانیزمی پیاده شود تا کلاس DbResourceManager از بهروزرسانی ورودیهای کششده اطلاع یابد تا آنها را ریفرش کند.
در ادامه درباره روشهای مختلف نحوه پیادهسازی قابلیت بهروزرسانی ورودیهای منابع در زمان اجرا با استفاده از پرووایدرهای منابع سفارشی بحث خواهد شد. همچنین راهحلهای مختلف استفاده از این پرووایدرهای سفارشی در جاهای مختلف پروژههای MVC شرح داده میشود.
البته مباحث پیشرفتهتری چون تزریق وابستگی برای پیادهسازی لایه ارتباط با دیتابیس در بیرون و یا تولید یک Factory برای تزریق کامل پرووایدر منابع از بیرون نیز جای بحث و بررسی دارد.
منابع
http://msdn.microsoft.com/en-us/library/aa905797.aspx
http://msdn.microsoft.com/en-us/library/system.web.compilation.resourceproviderfactory.aspx
http://www.dotnetframework.org/default.aspx/.../ResourceFallbackManager@cs
http://www.codeproject.com/Articles/14190/ASP-NET-2-0-Custom-SQL-Server-ResourceProvider
EF Code First #3
public partial class Sanad { public int Sanad_FixCode { get; set; } public int Sanad_Code { get; set; } public string Sanad_Date { get; set; } ..... }
در حال حاضر این کتابخانه از مفاهیم زیر پشتیبانی میکند:
- تبدیل کلاس به جدول با پشتیبانی از خصوصیت Table
- تبدیل پراپرتیها به ستون با پشتیبانی از خصوصیت هایی چون Column,Key,MaxLength,Required,Notmapped,DatabaseGenerated,Index
- پشتیبانی از primarykey و کلیدهای ترکیبی
- کلید خارجی و روابط یک به چند و پشتیبانی از cascade on delete
- فیلد غیر نال
برای شروع ابتدا کتابخانه مورد نظر را از Nuget با دستور زیر دریافت کنید:
Install-Package SQLite.CodeFirst
solution من شامل سه پروژه است یکی برای مدلها که شامل کلاسهای زیر برای تهیه یک دفترچه تلفن ساده است:
Person
public class Person { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public virtual ICollection<PhoneBook> Numbers { get; set; } }
PhoneBook
public class PhoneBook { public int Id { get; set; } public string Field{ get; set; } public string Number { get; set; } public virtual Person Person { get; set; } }
پروژه بعدی به نام سرویس که جهت پیاده سازی کلاسهای EF است و دیگری هم یک پروژهی WPF جهت تست برنامه.
در پروژهی سرویس ما یک کلاس به نام Context داریم که مفاهیم مربوط به پیاده سازی Context در آن انجام شده است:
public class Context:DbContext { public Context():base("constr") { } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); var initializer = new InitialDb(modelBuilder); Database.SetInitializer(initializer); } public DbSet<PhoneBook> PhoneBook { get; set; } public DbSet<Person> Persons { get; set; } }
اول اینکه در سطر اول متد بازنویسی شده onModelCreating، قرارداد مربوط به نامگذاری جداول را حذف میکنیم چرا که در صورت نبودن این خط، اسامی که کلاس sqllite برای آن در نظر خواهد گرفت با اسامی که برای انجام عملیات CURD استفاده میشوند متفاوت خواهد بود. برای مثال برای Person جدولی به اسم People خواهد ساخت ولی برای درج، آن را در جدول Person انجام میدهد که به خاطر نبودن جدول با خطای چنین جدولی موجود نیست روبرو میشویم.
نکتهی دوم اینکه در همین کلاس Context ما یک پیاده سازی جدید بر روی کلاس InitialDb داشته ایم که در زیر نمونه کد آن را میبینید:
public class InitialDb:SQLite.CodeFirst.SqliteCreateDatabaseIfNotExists<Context> { public InitialDb(DbModelBuilder modelBuilder) : base(modelBuilder) { } protected override void Seed(Context context) { var person = new Person() { FirstName = "ali", LastName = "yeganeh", Numbers = new List<PhoneBook>() { new PhoneBook() { Field = "Work", Number = "031551234" }, new PhoneBook() { Field = "Mobile", Number = "09123456789" }, new PhoneBook() { Field = "Home", Number = "031554321" } } }; context.Persons.Add(person); base.Seed(context); } }
سپس در پروژهی اصلی WPF در فایل AppConfig رشته اتصالی مورد نظر را وارد نمایید:
<connectionStrings> <add name="constr" connectionString="data source=.\phonebook.sqlite;foreign keys=true" providerName="System.Data.SQLite" /> </connectionStrings>
خطا:
The ADO.NET provider with invariant name 'System.Data.SQLite' is either not registered in the machine or application config file, or could not be loaded
قسمتی از فایل app.config:
<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" /> <provider invariantName="System.Data.SQLite" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" /> </providers> </entityFramework> <system.data> <DbProviderFactories> <remove invariant="System.Data.SQLite.EF6" /> <remove invariant="System.Data.SQLite" /> <add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".Net Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" /> </DbProviderFactories> </system.data>
کد Load پروژه WPF:
public MainWindow() { InitializeComponent(); var context=new Context(); var list= context.Persons.ToList(); var s = ""; foreach (var person in list) { s += person.FirstName + " " + person.LastName + " has these numbers:" + Environment.NewLine; foreach (var number in person.Numbers) { s += number.Field + " : " + number.Number + Environment.NewLine; } s += Environment.NewLine; } MessageBox.Show(s); }
دانلود مثال
مقدمه :
نوع دادهها، اجزای اصلی سازندهی یک زبان برنامه نویسی و شبیه قواعد هر زبانی هستند.
مفاهیمی که در این مطلب بررسی خواهد شد :
• Data Type نوع داده
• Variables متغیرها
• Naming Convention قراردادهای نامگذاری
• Value Type/Reference Type انواع مقداری و ارجاعی
• Stack/heap memory حافظه پشته و هرم
نوع داده
متغیرها
چک کردن سایز نوع داده (Data Type)
Console.WriteLine(sizeof(int)); Console.WriteLine(sizeof(char)); Console.WriteLine(sizeof(bool)); Console.WriteLine(sizeof(decimal)); Console.WriteLine(sizeof(float));
4 2 1 16 4
نکته : متد sizeof فقط برای نمایش اندازهی نوع دادههای مقداری (value type) میتواند مورد استفاده قرار گیرد.
چک کردن نوع داده
ما میتوانیم نوع دادهها را برای بدست آوردن کلاسی که به آن تعلق دارند، چک کنیم.
مثال :
int a = 23; float b = 3.14f; Console.WriteLine(a.GetType()); Console.WriteLine(b.GetType());
System.Int32 System.Single
چک کردن نوع دادهی دو شیء
فرض کنید 2 شیء را با نامهای obj1 و obj2 داریم که هر دو از نوع long هستند. برای اینکه این مقایسه را انجام دهیم، از متد Object.RefrenceEqual میتوان استفاده کرد.
مثال :
long obj1 = 356; long obj2 = 54; float obj3 = 234; Console.WriteLine(object.ReferenceEquals(obj1.GetType(), obj2.GetType())); Console.WriteLine(object.ReferenceEquals(obj1.GetType(), obj3.GetType()));
True False
تعریف یک متغیر ومقدار دهی به آن
برای استفاده از یک متغیر ابتداباید آن را تعریف کنیم :
//<data type> <variable name>; Int a;
مقداردهی اولیه یک متغیر
مقدار دهی اولیهی یک متغیر با استفاده از عملگر = و نوشتن مقدار مورد نظر برای ذخیره کردن در متغیر، در سمت راست عملگر اتفاق خواهد افتاد.
//<data type> <variable name>=value; Int a=23; Int a;//declare تعریف a=23;//مقدار دهی اولیه initializing Int a=23;//تعریف و مقدار دهی در یک خط Int a,b,c=23;//تعریف چند متغیر و مقدار دهی در یک خط
قرار دادهای نام گذاری متغیرها :
در دنیای برنامه نویسی دو نوع قرار داد نام گذاری بسیار متداول وجود دارند:
1- camelCase : در این قرار داد، حرف اول کلمهی اول، بصورت کوچک و حرف اول از کلمهی دوم، بصورت بزرگ نوشته خواهد شد. برای مثال: firstName,lastName
2- PascalCase : در این قرار داد حروف ابتدایی دو کلمهی مجاور، بصورت بزرگ نوشته خواهند شد: FirstName,LastName
چند نکته :
• نامگذاری متغیرها را میتوانید با علامت _ و یا @ شروع کنید.
• کلمات کلیدی (key word) سی شارپ نمیتوانند به عنوان نام متغیر مورد استفاده قرار بگیرند (مگر آنکه با @ شروع شوند).
• در بین نام متغیر نباید فضای خالی وجود داشته باشد. کاراکترهای سازندهی متغیر میتوانند اعداد، حروف و زیر خط باشند.
لیستی از نام گذاریهای مجاز:
int abc; long _abcd; float @abcd; bool main_button; decimal piValue; string firstName; string first_name; bool button55_on;
long _a.5bc5d; float @ab cd; decimal pi@Value; //استفاده از کلمات کلیدی سی شارپ که کامپایلر آنها را مجاز نمیداند bool class; string namespace; string string; int static;
در ادامه کمی در مورد نوع دادهها بحث خواهیم کرد.
در سی شارپ دو مدل نوع داده وجود دارد:
• انواع مقداری Value Type
• انواع ارجاعی یا اشارهای Reference Type
انواع مقداری (Value Type) :
• انواع مقداری مستقیما حاوی دادهها هستند. اگر یک متغیر از نوع مقداری را به یک متغیر دیگر تخصیص دهید، مقدار آنها مستقیما کپی میشوند؛ برعکس نوعهای اشارهای که با نخصیص یک متغیر به یک متغیر دیگر، تنها اشارهگر به مقدار شیء کپی خواهد شد و نه خود شیء.
• کلیه نوعهای مقداری از کلاس ValueType مشتق شدهاند.
• در فضای stack به آنها حافظه تخصیص داده میشود.
• نمیتوانند مقدار null بپذیرند. البته با قابلیت nullabletype امکان تخصیص مقدار null به نوع دادههای مقداری نیز مهیا شده است.
• همه نوعهای دادههای مقداری، یک سازنده پیش فرض دارند که به صورت ضمنی کار مقدار دهی اولیه برای آنها را انجام میدهد. برای مطالعه بیشتر درباره مقادیر پیش فرض به اینجا مراجعه کنید.
انواع مقداری به دو دستهی اصلی تقسیم میشود :
• Structs
• Enumerations
طبقه بندی Structs به صورت زیر است :
• Numeric Type
* Integral Type : sbyte,short,ushort,int,uint,long,ulong,char
* Floating-Point Types : float,double
* Decimal : decimal
• Bool دو مقدار true و false
• User Defined Struct
نوع داده نال (تهی) پذیر (nullable Type) و چگونگی تعریف آن
< data type >? < variable name >= null; //syntax
int? a = null; //assigning null int? b = 55; //assigning null and a value var? c = 55 //it will give error
نکته : var نمیتواند بصورت nullable تعریف شود.
برای چک کردن مقدار در انواع تهی پذیر (nullable) دو خصوصیت وجود دارد:
• HasValue
اگر مقداری در متغیر وجود داشته باشد ارزش true بازگردانده میشود؛ در غیر اینصورت ارزش false
• Value
مقدار واقعی متغیر را باز میگرداند.
مثال :
int? a = null; int? b = 22; Console.WriteLine(a.HasValue); //------------ Console.WriteLine(b.HasValue); Console.WriteLine(b.Value);
False True 22
انواع ارجاعی Reference Type
انواع ارجاعی مستقیما حاوی اطلاعات نیستند و ارجاعی هستند به آدرسی از حافظه که حاوی اطلاعات واقعی است. به بیانی دیگر، اشارهگری به آدرسی از حافظه هستند.
• انواع ارجاعی بصورت غیر مستقیم حاوی دادهها هستند.
• در بخشی از حافظه که به آن heap میگوییم، به آنها فضا اختصاص داده میشود.
• میتوانند بصورت null (بدون مقدار) باشند.
انواع ارجاعی نیز به دو دستهی کلی تقسیم میشوند :
• انواع از پیش تعریف شده
Object,string,dynamic
• انواع تعریف شده توسط کاربر
class,interface,delegate
نکته : آدرس مکانی از حافظه که دادهها در آن قرار دارند، در بخش پشته یا Stack ذخیره میشود و دادهها در فضای heap ذخیره میشوند.
مثال :
test obj; //allocating reference on stack obj= new test(55);//allocating object on heap
نکته : دو متغیر از نوع ارجاعی میتوانند به یک آدرس از حافظه اشاره کنند. در شکل زیر این موضوع نشان داده شده است.
در شکل زیر طبقه بندی نوع دادهها در سی شارپ نشان داده شده است :
وقتی از یک متغیر مقداری را به یک متغیر دیگر تخصیص میدهیم، یک کپی جدید از آن در فضای stack ایجاد میشود. بدین معنی که محتوای دو متغیر یکسان هستند، ولی در دو بخش مجزای در حافظهی Stack قرار دارند. به همین خاطر تغییر محتوای یک متغیر، محتوای متغیر دیگر را تغییر نمیدهد.
مثال :
int a = 55;//declare a and initialize int copya = a;//copya contains the copy of value a
• عملیات کپی، در نوع دادهی ارجاعی
test obj; obj=new test(23); test objCopy; objCopy = obj;
دیاگرام حافظهی قطعه کد بالا به شکل زیر است :
تخصیص حافظه در بخش Stack و Heap به متغیرها
سیستم عامل و net CLR. حافظه را به دو بخش stack و heap تقسیم بندی میکنند.
در این قسمت بیشتر یک سری از ماژولها را به شما در قالب جداول گروه بندی شده معرفی خواهیم کرد :
همانطور که در قسمتهای قبلی گفتیم سرور IIS آماده خصوصی سازی و کار بر اساس علائق شماست؛ ولی توجه داشته باشید حذف تمامی ماژولها ممکن است اثرات جانبی هم داشته باشد. در اینجا ما ماژول هایی را به شما معرفی میکنیم که بدانید کار هر ماژول چیست تا مثلا با حذف ماژولی، امنیت وب سایت خود را به خطر نیندازید :
ماژولهای سودمند یا utility
نام ماژول: | UriCacheModule |
توضیح: | این ماژول نوعی کش برای URLها به شمار میرود. موقعی که url درخواست میشود، اطلاعات در اولین درخواست خوانده شده و کش میشود و اگر دوباره همان url درخواست شود، بدون خواندن تنظیمات و بر اساس تنظیمات قبلی، کار url مربوطه را انجام میدهد تا اطلاعات پیکربندی تغییر کند و بر اساس اطلاعات جدید، خود را به روز کند. |
تگ قابل پیکربندی: | لازم ندارد |
وابستگی: | ندارد |
اثرات حذف آن: | کارایی سیستم کاهش مییابد و سیستم مجبور است برای هر درخواست فایل پیکربندی را بخواند. |
نام ماژول : | FileCacheModule |
توضیح : | فایل هندلِ فایلهایی که قبلا در سرور باز شدهاند را کش میکند تا در صورت نیاز در دفعات بعدی سریعتر عمل کند. |
تگ قابل پیکربندی : | لازم ندارد . |
وابستگی : | ندارد. |
اثرات حذف آن : | کارایی سیستم کاهش مییابد. سیستم در هر اجرای دستور مربوط به فایلها باید فایل هندل را به دست آورد. |
نام ماژول : | TokenCacheModule |
توضیح : | توکنهای امنیتی ویندوز که پسوردهایی بر اساس authentication schemes هستند را کش میکند (anonymous authentication, basic authentication, IIS client certificate authentication ) |
تگ قابل پیکربندی : | لازم ندارد |
وابستگی : | ندارد |
اثرات حذف آن : | کارایی سیستم به شدت پایین میآید. کاربر باید با هر درخواستی لاگین کند. یکی از اصلیترین ضربهها با حذف این ماژول این است که اگر مثلا یک پسورد از یک فایل html محافظت میکند و این صفحه به 50 تصویر ارجاع دارد، 51 بار باید درخواست لاگین اجرا گردد یا شاید هم بدتر |
MANAGED ENGINE: ASP.NET INTEGRATION
نام ماژول : | ManagedEngine |
توضیح : | مدیریت ماژولهای native و مدیریت شده |
تگ قابل پیکربندی : | |
وابستگی : | ندارد |
اثرات حذف آن : | مشخصا غیرفعال شدن asp.net integrated و غیر فعال شدن تمامی ماژولها و هندلرهای تگ وب کانفیگ یا داخل فایل کانفیگ IIS که در مقالات قبلی به تفصیل بیان کردهایم. |
IIS 7 NATIVE MODULES
نام ماژول : | HttpCacheModule |
توضیح : | مدیریت کش خروجی در htttp.sys بر اساس پیکربندی مثل تعریف سایز کش و ... |
تگ قابل پیکربندی : | System.webServer/caching |
وابستگی : | ندارد. |
اثرات حذف آن : | محتوا دیگر به صورت کرنل مد، کش نمیشود و کش پروفایل هم ندید گرفته میشود و احتمالا بر کارآیی و استفاده از منابع هم اثر میگذارد. |
نام ماژول : | DynamicCompressionModule |
توضیح : | پیاده سازی in-memory compression در محتوای پویا |
تگ قابل پیکربندی : | system.webServer/httpCompression and system.webServer/urlCompression. |
وابستگی : | وابستگی ندارد چرا که به طور پیش فرض غیرفعال است. |
نام ماژول : | StaticCompressionModule |
توضیح : | پیادسازی فشرده سازی در محتوای ایستا و برای فایلهای سیستمی از نوع in memory |
تگ قابل پیکربندی : | system.webServer/httpCompression and system.webServer/urlCompression |
وابستگی : | ندارد. |
اثرات حذف آن : | در صورت عدم فشرده سازی بر مصرف ترافیک تاثیر گذار است. |
نام ماژول : | DefaultDocumentModule |
توضیح : | پیاده سازی یک لیست سند پیش فرض. درخواستها مدام پشت سر هم میآیند و این درخواستهای پشت سرهم، به سند پیش فرض هدایت میشوند. همان پنجره ای که شما به ترتیب فایلهای index.htm,index.asp,default.aspx و... را تعیین میکنید. |
تگ قابل پیکربندی : | system.webServer/defaultDocument |
وابستگی : | ندارد. |
اثرات حذف آن : | درخواست را به ریشه هدایت میکند. مثلا برای localhost صفحه 404 باز میگرداند و اگر directoryBrowsing فعال باشد لیستی از دایرکتوری ریشه را باز میگرداند. |
نام ماژول : | DirectoryListingModule |
توضیح : | پیادی سازی لیستی از محتویات یک دایرکتوری |
تگ قابل پیکربندی : | system.webServer/directoryBrowse |
وابستگی : | ندارد. |
اثرات حذف آن : | اگر این ماژول و ماژول قبلی غیرفعال باشند response نهایی خالی است. |
نام ماژول : | ProtocolSupportModule |
توضیح : | پیاده سازی اختصاصی از response header پیاده سازی تنظیمات trace و HTTP verbs. پیاده سازی تنظیمات مربوطه به keep-alive بر اساس پیکربندی |
تگ قابل پیکربندی : | system.webServer/httpProtocol |
وابستگی : | ندارد. |
اثرات حذف آن : | بازگرداندن پیام خطای "405 Method not allowed". |
نام ماژول : | HttpRedirectionModule |
توضیح : | پیاده سازی عملیات انتقال یا redirect |
تگ قابل پیکربندی : | system.webServer/httpRedirect |
وابستگی : | ندارد. |
اثرات حذف آن : | خطر امنیتی: اگر منابعی با redirect کردن محافظت میشوند، از این پس در دسترسند. |
نام ماژول : | ServerSideIncludeModule |
توضیح : | حمایت از فایل shtm یا shtml و ... |
تگ قابل پیکربندی : | system.webServer/serverSideInclude |
وابستگی : | ندارد. |
اثرات حذف آن : | این فایلها به صورت متنی نمایش داده میشوند |
نام ماژول : | StaticFileModule |
توضیح : | فایلهای ایستا را به همراه پسوند ارسال میکند. مثل jpg,html و نوع محتوا را بر اساس staticContent/mimeMap پیکربندی میکند. |
تگ قابل پیکربندی : | system.webServer/staticContent |
وابستگی : | ندارد. |
اثرات حذف آن : | فایلهای ایستا دیگر ارائه نشده و به جای آن خطای 404 بازگشت داده میشود. |
نام ماژول : | AnonymousAuthenticationModule |
توضیح : | پیاده سازی سیستم شناسایی افراد ناشناس. همانطور که میدانید در یک وب سایت حداقل محتوایی برای افرادی بدون داشتن اکانت هم وجود دارد. برای اینکار یک شیء httpuser ایجاد میکند. |
تگ قابل پیکربندی : | system.webServer/security/authentication/anonymousAuthentication |
وابستگی : | ندارد. |
اثرات حذف آن : | حداقل باید یک سیستم امنیتی برای شناسایی یا authenticate وجود داشته باشد. httpuser یک ساختار داده ای در IIS میباشد و در صورت نبودن هیچ سیستم شناسایی وجود نداشته و در نبود شیء httpuser سیستم خطای 401.2 را تولید میکند. |
نام ماژول : | CertificateMappingAuthenticationModule |
توضیح : | مجوز SSL را به Active Directory نگاشت میکند. |
تگ قابل پیکربندی : | system.webServer/security/authentication/clientCertificateMappingAuthentication |
وابستگی : | برای اینکه این ماژول وظیفه خود را انجام دهد باید تنظیمات SSL انجام شود و همچنین سیستم IIS جزئی از دامنه Active directory باشد |
اثرات حذف آن : | درخواستها، نرمال رسیدگی میشوند انگار SSL وجود ندارد. |
نام ماژول : | BasicAuthenticationModule |
توضیح : | پیاده سازی پایهای و روتین شناسایی کاربران بر اساس آن چیزی که در استانداد زیر آمده است |
تگ قابل پیکربندی : | system.webServer/security/authentication/basicAuthentication |
وابستگی : | None. |
اثرات حذف آن : | حداقل باید یک سیستم امنیتی برای شناساسایی یا authenticate وجود داشته باشد. httpuser یک ساختار دادهای در IIS میباشد و در صورت نبود، هیچ سیستم شناسایی یافت نشده و نبود شیء httpuser در سیستم، خطای 401.2 را تولید میکند. |
نام ماژول : | WindowsAuthenticationModule |
توضیح : | ((windows Authentication (NTLM or Negotiate (Kerberos |
تگ قابل پیکربندی : | system.webServer/security/authentication/windowsAuthentication |
وابستگی : | ندارد. |
اثرات حذف آن : | حداقل باید یک سیستم امنیتی برای شناسایی یا authenticate وجود داشته باشد. httpuser یک ساختار داده ای در IIS میباشد و در صورت نبود، هیچ سیستم شناسایی یافت نشده و نبود شیء httpuser در سیستم، خطای 401.2 را تولید میکند. |
نام ماژول : | DigestAuthenticationModule |
توضیح : | پیاده سازی سیستم شناسایی دیاجست بر اساس RFC 2617 . |
تگ قابل پیکربندی : | system.webServer/security/authentication/digestAuthentication |
وابستگی : | IIS باید بخشی از دامنه Active Directory باشد. |
اثرات حذف آن : | حداقل باید یک سیستم امنیتی برای شناسایی یا authenticate وجود داشته باشد.
httpuser یک ساختار داده ای در IIS میباشد و در صورت نبود، هیچ سیستم
شناسایی یافت نشده و نبود شیء httpuser در سیستم، خطای 401.2 را تولید
میکند. |
نام ماژول : | IISCertificateMappingAuthenticationModule |
توضیح : | پیاده سازی نگاشت مجوزهای IIS، نگهداری و ذخیره اطلاعات همه نگاشتها و مجوزهای کاربری چون SSL client certificates |
تگ قابل پیکربندی : | system.webServer/iisClientCertificateMappingAuthentication |
وابستگی : | اطلاعات SSL به همراه دریافت client certificates جهت پیکربندی این ماژول |
اثرات حذف آن : | حداقل باید یک سیستم امنیتی برای شناسایی یا authenticate وجود داشته باشد.
httpuser یک ساختار داده ای در IIS میباشد و در صورت نبود، هیچ سیستم
شناسایی یافت نشده و نبود شیء httpuser در سیستم، خطای 401.2 را تولید
میکند. |
نام ماژول : | UrlAuthorizationModule |
توضیح : | پیاده سازی authorization بر اساس قوانین پیکربندی شده |
تگ قابل پیکربندی : | system.webServer/security/authorization |
وابستگی : | ندارد. |
اثرات حذف آن : | محتواهای محافظت شده توسط authorization دیگر محافظت نمیشوند. |
نام ماژول : | IsapiModule |
توضیح : | پیاده سازی ISAPI Extension |
تگ قابل پیکربندی : | system.webServer/isapiCgiRestriction |
وابستگی : | ندارد. |
اثرات حذف آن : | هندلرهای معرفی شده در بخش IsapiModule و تگ handlers دیگر اجرا نمیشوند |
نام ماژول : | IsapiFilterModule |
توضیح : | پیاده سازی ISAPI filter |
تگ قابل پیکربندی : | system.webServer/isapiFilters |
وابستگی : | ندارد. |
اثرات حذف آن : | اگر برنامه ای از ISAPI filter استفاده میکند، در اجرا دچار مشکل خواهد شد. |
نام ماژول : | IpRestrictionModule |
توضیح : | یک سیستم تشخیص دسترسی بر اساس آی پیهای ورژن4 |
تگ قابل پیکربندی : | system.webServer/security/ipSecurity |
وابستگی : | IPv4 stack باید نصب شود. |
اثرات حذف آن : | کلاینت هایی که IP هایشان در IPsecurity لیست شدهاند ندید گرفته میشوند |
نام ماژول : | RequestFilteringModule |
توضیح : | پیاده سازی یک مجموعه قدرتمند از قوانین امنیتی که درخواستهای مشکوک را پس میزند. |
تگ قابل پیکربندی : | system.webServer/security/requestFiltering |
وابستگی : | ندارد. |
اثرات حذف آن : | دیگر قوانین امنیتی اجرا نخواهند شد و سبب وجود مشکلات امنیتی میشود. |
نام ماژول : | CustomLoggingModule |
توضیح : | پیاده سازی اینترفیس ILogPlugin در سمت IIS، به مشتریان اجازه میدهد تا لاگهای خود را توسعه دهند. هر چند این روش توصیه نمیشود و توصیه کارشناس مایکروسافت استفاده از یک ماژول دست نویس از نوع RQ_LOG_REQUEST می باشد. Implements the ILogPlugin interface on top of IIS. ILogPlugin is a previous COM implementation that allowed customers to extend IIS logging. We do not not recommend extending IIS using this interface. Instead, customers should write a module and subscribe to the RQ_LOG_REQUEST notification. |
تگ قابل پیکربندی : | system.webServer/httpLogging and system.applicationhost/sites/site/logFile/customLogPluginClsid |
وابستگی : | ندارد. |
اثرات حذف آن : | مسلما پلاگینهایهای این اینترفیس از کار میافتند که سیستم ODBC Logging هم جز آن است. |
نام ماژول : | CustomErrorModule |
توضیح : | پیاده سازی مدیریت خطاهای ویژه |
تگ قابل پیکبرندی : | system.webServer/httpErrors |
وابستگی : | None. |
اثرات حذف آن : | در صورتی که خطایی از هسته باشد، نتیجه یک صفحه، با توضیح مختصری از خطا خواهد بود. در غیر این صورت اگر خطا از برنامه یا کامپوننتی باشد جزئیات خطا فاش خواهد شد |
نام ماژول : | HttpLoggingModule |
توضیح : | پیاده سازی سیستم logging استاندارد http.sys |
تگ قابل پیکربندی : | system.applicationHost/log and system.webServer/httpLogging |
وابستگی : | ندارد. |
اثرات حذف آن : | از کار افتادن سیستم لاگ |
نام ماژول : | FailedRequestsTracingModule |
توضیح : | پیاده سازی سیستم ردیابی درخواستهای ناموفق و اجرای قوانین، طبق پیکربندی |
تگ قابل پیکربندی : | system.webServer/tracing and system.webServer/httpTracing |
وابستگی : | ندارد. |
اثرات حذف آن : | Tracing http requests will no longer work. |
نام ماژول : | RequestMonitorModule |
توضیح : | پیاده سازی IIS Run-time State and Control Interface یا به اختصار RSCA . به کاربران اجازه میدهد از اطلاعات، حین اجرا، کوئری بگیرند. مثل درخواست درحال اجرای جاری، آغاز به کار یا توقف وب سایت و دامنههای اپلیکیشن در حال اجرای جاری |
تگ قابل پیکربندی : | ندارد. |
وابستگی : | ندارد. |
اثرات حذف آن : | ابزارهای مرتبط با این موضوع از کار میافتند |
نام ماژول : | CgiModule |
توضیح : | پیاده سازی CGI در سمت IIS |
تگ قابل پیکبرندی : | system.webServer/cgi and system.webServer/isapiCgiRestriction |
وابستگی : | ندارد. |
اثرات حذف آن : | برنامههای CGI متوقف میشوند |
نام ماژول : | TracingModule |
توضیح : | پیاده سازی سیستم ردیابی ETW |
تگ قابل پیکربندی : | system.webServer/httpTracing |
وابستگی : | ندارد. |
اثرات حذف آن : | باعث از کار افتادن سیستم مربوطه میشود |
نام ماژول : | ConfigurationValidationModule |
توضیح : | اعتبارسنجی تنظیمات برنامه ASP.Net که به حالت integrate انتقال یافته است |
تگ قابل پیکربندی : | system.webServer/Validation |
وابستگی : | ندارد. |
اثرات حذف آن : | عدم اعتبارسنجی و در نتیجه عدم نمایش خطاها |
MANAGED MODULES:
نام ماژول : | OutputCache |
توضیح : | پیاده سازی output caching |
تگ قابل پیکربندی : | system.web/caching/outputCache |
وابستگی : | نیاز به ManagedEngine . |
اثرات حذف آن : | عدم اجرای output cache |
نام ماژول : | Session |
توضیح : | مدیریت سشن ها |
تگ قابل پیکربندی : | system.web/sessionState |
وابستگی : | نیاز به ManagedEngine . |
اثرات حذف آن : | سشنها از دسترس خارج میشوند. |
نام ماژول : | WindowsAuthentication |
توضیح : | |
تگ قابل پیکربندی : | system.web/authentication |
وابستگی : | نیاز به ManagedEngine . |
اثرات حذف آن : | این حالت قابل اجرا نخواهد بود |
نام ماژول : | FormsAuthentication |
توضیح : | |
تگ قابل پیکربندی : | system.web/authentication |
وابستگی : | نیاز به ManagedEngine . |
اثرات حذف آن : | این حالت قابل اجرا نیست و کاربران مجوز دار هم نمیتوانند به منابع محافظت شده دسترسی داشته باشند. |
نام ماژول : | DefaultAuthentication |
توضیح : | اطمینان از وجود شی Authentication در context مربوطه |
تگ قابل پیکربندی : | system.web/authentication |
وابستگی : | نیاز به ManagedEngine . |
اثرات حذف آن : | اگر مد Forms authentication انتخاب شده باشد بر روی بعضی از کاربران ناشناس کار نخواهد کرد و رویداد DefaultAuthentication.OnAuthenticate اجرا نخواهد شد. |
نام ماژول : | RoleManager |
توضیح : | |
تگ قابل پیکربندی : | |
وابستگی : | نیاز به ManagedEngine . |
اثرات حذف آن : | این قابلیت در دسترس نمیباشد |
نام ماژول : | UrlAuthorization |
توضیح : | |
تگ قابل پیکربندی : | system.web/authorization. |
وابستگی : | نیاز به ManagedEngine . |
اثرات حذف آن : | باعث از کار افتادن asp.net authorization و فاش شدن بعضی اطلاعات و همچنین دیگر تهدیدات امنیتی |
نام ماژول : | AnonymousIdentification |
توضیح : | |
تگ قابل پیکربندی : | |
وابستگی : | نیاز به ManagedEngine . |
اثرات حذف آن : | The anonymous identification feature used by the ASP.NET Profile will not work. |
نام ماژول : | Profile |
توضیح : | |
تگ قابل پیکربندی : | |
وابستگی : | ManagedEngine module must be installed. |
اثرات حذف آن : | ASP.Net Profile از کار خواهد افتاد |
نام ماژول : | UrlMappingsModule |
توضیح : | تبدیل یک Url واقعی به یک Url کاربرپسند |
تگ قابل پیکبرندی : | |
وابستگی : | نیاز به ManagedEngine . |
اثرات حذف آن : | نگاشت Urlها صورت نمیگیرد |
چرا XML و چرا پشتیبانی توکار از آن در SQL Server
فیلدهای XML از سال 2005 به امکانات توکار SQL Server اضافه شدهاند و بسیاری از مزایای دنیای NoSQL را درون SQL Server رابطهای مهیا میسازند. برای مثال با تعریف یک فیلد به صورت XML، میتوان از هر ردیف به ردیفی دیگر، اطلاعات متفاوتی را ذخیره کرد؛ به این ترتیب امکان کار با یک فیلد که میتواند اطلاعات یک شیء را قبول کند و در حقیقت امکان تعریف اسکیمای پویا و متغیر را در کنار امکانات یک بانک اطلاعاتی رابطهای که از اسکیمای ثابت پشتیبانی میکند، میسر میشود.
همچنین SQL Server در این حالت قابلیتی را ارائه میدهد که در بسیاری از بانکهای اطلاعاتی NoSQL میسر نیست. در اینجا در صورت نیاز و لزوم میتوان اسکیمای کاملا مشخصی را به یک فیلد XML نیز انتساب داد؛ هر چند این مورد اختیاری است و میتوان یک un typed XML را نیز بکار برد. به علاوه امکانات کوئری گرفتن توکار از این اطلاعات را به کمک XPath ترکیب شده با T-SQL، نیز فراموش نکنید.
بنابراین اگر یکی از اهداف اصلی گرایش شما به سمت دنیای NoSQL، استفاده از امکان تعریف اطلاعاتی با اسکیمای متغیر و پویا است، فیلدهای نوع XML اس کیوال سرور را مدنظر داشته باشید.
یک مثال عملی: فناوری Azure Dev Fabric's Table Storage (نسخه Developer ویندوز Azure که روی ویندوزهای معمولی اجرا میشود؛ یک شبیه ساز خانگی) به کمک SQL Server و فیلدهای XML آن طراحی شده است.
چرا XML و چرا پشتیبانی توکار از آن در SQL Server
یک سند XML معمولا بیشتر از یک قطعه داده را در خود نگهداری میکند و نوع دادهی پیچیده محسوب میشود؛ برخلاف دادههایی مانند int یا varchar که نوعهایی ساده بوده و تنها یک قطعه از اطلاعات خاصی را در خود نگهداری میکنند. بنابراین شاید این سؤال مطرح شود که چرا از این نوع داده پیچیده در SQL Server پشتیبانی شدهاست؟
- از سالهای نسبتا دور، از XML برای انتقال دادهها بین سیستمها و سکوهای کاری مختلف استفاده شدهاست.
- استفادهی گستردهای در برنامههای تجاری دارد.
- بسیاری از فناوریهای موجود از آن پشتیبانی میکنند.
برای مثال اگر با فناوریهای مایکروسافتی کار کرده باشید، به طور قطع حداقل در یک یا چند قسمت از آنها، مستقیما از XML استفاده شدهاست.
بنابراین با توجه به اهمیت و گستردگی استفاده از آن، بهتر است پشتیبانی توکاری نیز از آن داخل موتور یک بانک اطلاعاتی، پیاده سازی شده باشد. این مساله سهولت تهیه پشتیبانهای خودکار، بازیابی آنها و امنیت یکپارچه با SQL Server را به همراه خواهد داشت؛ به همراه تمام زیرساختهای مهیای در SQL Server.
روشهای مختلف ذخیره سازی XML در بانکهای اطلاعاتی رابطهای
الف) ذخیره سازی متنی
این روش نیاز به نگارش خاصی از SQL Server یا بانک اطلاعاتی الزاما خاصی نداشته و با تمام بانکهای اطلاعاتی رابطهای سازگار است؛ مثلا از فیلدهای varchar برای ذخیره سازی آن استفاده شود. مشکلی که این روش به همراه خواهد داشت، از دست دادن ارزش یک سند XML و برخورد متنی با آن است. زیرا در این حالت برای تعیین اعتبار آن یا کوئری گرفتن از آنها نیاز است اطلاعات را از بانک اطلاعاتی خارج کرده و در لایهای دیگر از برنامه، کار جستجو پردازش آنها را انجام داد.
ب) تجزیه XML به چندین جدول رابطهای
برای مثال یک سند XML را درنظر بگیرید که دارای اطلاعات شخص و خریدهای او است. میتوان این سند را به چندین فیلد در چندین جدول مختلف رابطهای تجزیه کرد و سپس با روشهای متداول کار با بانکهای اطلاعاتی رابطهای از آنها استفاده نمود.
ج) ذخیره سازی آنها توسط فیلدهای خاص XML
در این حالت با استفاده از فیلدهای ویژه XML میتوان از فناوریهای مرتبط با XML تمام و کمال استفاده کرد. برای مثال تهیه کوئریهای پیچیده داخل همان بانک اطلاعاتی بدون نیاز به تجزیه سند به چندین جدول و یا خارج کردن آنها از بانک اطلاعاتی و جستجوی بر روی آنها در لایهای دیگر از برنامه.
موارد کاربرد XML در SQL Server
کاربردهای مناسب
- اطلاعات، سلسله مراتبی و تو در تو هستند. XQuery و XPath در این موارد بسیار خوب عمل میکند.
- ساختار قسمتی از اطلاعات ثابت است و قسمتی از آن خیر. برای نمونه، یک برنامهی فرم ساز را درنظر بگیرید که هر فرم آن هر چند دارای یک سری خواص ثابت مانند نام، گروه و امثال آن است، اما هر کدام دارای فیلدهای تشکیل دهنده متفاوتی نیز میباشد. به این ترتیب با استفاده از یک فیلد XML، دیگری نیازی به نگران بودن در مورد نحوه مدیریت اسکیمای متغیر مورد نیاز، نخواهد بود.
نمونهی دیگر آن ذخیره سازی خواص متغیر اشیاء است. هر شیء دارای یک سری خواص ثابت است اما خواص توصیف کنندهی آنها از هر رکورد به رکوردی دیگر متفاوت است.
کاربردهای نامناسب
- کل اطلاعات را داخل فیلد XML قرار دادن. هدف از فیلدهای XML قرار دادن یک دیتابیس داخل یک سلول نیست.
- ساختار تعریف شده کاملا مشخص بوده و به این زودیها هم قرار نیست تغییر کند. در این حالت استفاده از قابلیتهای رابطهای متداول SQL Server مناسبتر است.
- قرار دادن اطلاعات باینری بسیار حجیم در سلولهای XML ایی.
تاریخچهی پشتیبانی از XML در نگارشهای مختلف SQL Server
الف) SQL Server 2000
در SQL Server 2000 روش (ب) توضیح داده شده در قسمت قبل، پشتیبانی میشود. در آن برای تجزیه یک سند XML به معادل رابطهای آن، از تابعی به نام OpenXML استفاده میشود و برای تبدیل این اطلاعات به XML از روش Select … for XML میتوان کمک گرفت. همچنین تاحدودی مباحث XPath Queries نیز در آن گنجانده شدهاست.
ب) SQL Server 2005
در نگارش 2005 آن، برای اولین بار نوع دادهای ویژه XML معرفی گشت به همراه امکان تعریف اسکیمای XML و اعتبارسنجی آن و پشتیبانی از XQuery برای جستجوی سریع بر روی دادههای XML داخل همان بانک اطلاعاتی، بدون نیاز به استخراج اطلاعات XML و پردازش مجزای آنها در لایهای دیگر از برنامه.
ج) SQL Server 2008 به بعد
در اینجا فاز نگهداری این نوع داده خاص شروع شده و بیشتر شامل یک سری بهبودهای کوچک در کارآیی و نحوهی استفاده از آنها میشود.
استفاده از XML با کمک SQLCLR
از SQL Server 2005 به بعد، امکان استفاده از کلیهی امکانات موجود در فضای نام System.Xml دات نت، در SQL Server نیز به کمک SQL CLR مهیا شدهاست. همچنین از SQL Server 2008 به بعد، امکانات فضای نام System.Xml.Linq و مباحث LINQ to XML نیز توسط SQL CLR پشتیبانی میشوند.
البته این امکانات در SQL Server 2005 نیز قابل استفاده هستند، اما اسمبلی شما unsafe تلقی میشود. پس از آزمایشات و بررسی کافی، فضای نام مرتبط با LINQ to XML و امکانات آن، به عنوان اسمبلیهایی امن و قابل استفاده در SQL Server 2008 به بعد، معرفی شدهاند.
مزایای وجود فیلد ویژه XML در SQL Server
پس از اینکه فیلدهای XML به صورت یک نوع داده بومی بانک اطلاعاتی SQL Server معرفی شدند، مزایای ذیل بلافاصله در اختیار برنامه نویسها قرار گرفت:
- امکان تعریف آنها به صورت یک ستون جدولی خاصی
- استفاده از آنها به عنوان یک پارامتر رویههای ذخیره شده
- امکان تعریف خروجی توابع scalar سفارشی تعریف شده به صورت XML
- امکان تعریف متغیرهای T-SQL از نوع XML
برای مثال در اینجا نحوهی تعریف یک جدول جدید دارای فیلدی از نوع XML را مشاهده میکنید:
CREATE TABLE xml_tab ( id INT, xml_col XML )
- امکان تعریف ایندکسهای XML ایی اضافه شدهاست.
چه نوع XML ایی را میتوان در فیلدهای XML ذخیره کرد؟
فیلدهای XML امکان ذخیره سازی دادههای XML خوش فرم را مطابق استاندارد یک XML، دارند. حداکثر اندازه قابل ذخیره سازی در یک فیلد XML دو گیگابایت است.
البته امکانات مهیای در SQL Server در بسیاری از موارد فراتر از استاندارد یک XML هستند. به این معنا که در فیلدهای XML میتوان Documents و یا Fragments را ذخیره سازی کرد. یک سند XML یا Document حاوی تنها یک ریشه اصلی است؛ اما یک Fragment میتواند بیش از یک ریشه اصلی را در خود ذخیره کند. یک مثال:
DECLARE @xml_tab TABLE (xml_col XML) -- document INSERT @xml_tab VALUES ('<person/>') -- fragment INSERT @xml_tab VALUES ('<person/><person/>') SELECT * FROM @xml_tab
DECLARE @xml_tab TABLE (xml_col XML) -- text only INSERT @xml_tab VALUES ('data data data .....') -- empty string INSERT @xml_tab VALUES ('') -- null value INSERT @xml_tab VALUES (null) SELECT * FROM @xml_tab
به علاوه باید دقت داشت که در SQL Server نوع دادهای XML برای ذخیره سازی دادهها بکار گرفته میشود. به این معنا که در اینجا پیشوندهای فضاهای نام XML بیمعنا هستند.
DECLARE @xml_tab TABLE (xml_col XML) INSERT @xml_tab VALUES ('<doc/>') INSERT @xml_tab VALUES ('<doc xmlns="http://www.doctors.com"/>') -- این سه سطر در عمل یکی هستند INSERT @xml_tab VALUES ('<doc xmlns="http://www.documents.com"/>') INSERT @xml_tab VALUES ('<dd:doc xmlns:dd="http://www.documents.com"/>') INSERT @xml_tab VALUES ('<rr:doc xmlns:rr="http://www.documents.com"/>') SELECT * FROM @xml_tab
Encoding ذخیره سازی دادههای XML
SQL Server امکان ذخیره سازی اطلاعات متنی را به فرمت UFT8، اسکی و غیره، دارد. اما جهت پردازش فیلدهای XML و ذخیره سازی آنها از Collation پیش فرض بانک اطلاعاتی کمک خواهد گرفت. البته ذخیره سازی نهایی آن همیشه با فرمت UCS2 است (یونیکد دو بایتی).
DECLARE @xml_tab TABLE (id INT, xml_col XML) INSERT INTO @xml_tab VALUES ( 5, N'<?xml version="1.0" encoding="utf-8"?> <doc1> <row name="vahid"></row> </doc1> ')
XML parsing: line 1, character 38, unable to switch the encoding
برای حل این مشکل باید N ابتدای رشته را حذف کرد. روش دوم، معرفی و استفاده از utf-16 است بجای utf-8 در ویژگی encoding.
همچنین در این حالت اگر encoding را utf-16 معرفی کنیم و ابتدای رشته در حال ذخیره سازی N قرار نگیرد، باز با خطای unable to switch the encoding مواجه خواهیم شد.
نحوهی ذخیره سازی اطلاعات XML ایی در SQL Server
SQL Server فرمت اطلاعات XML وارد شده را حفظ نمیکند. برای مثال اگر قطعه کد زیر را اجرا کنید
DECLARE @xml_tab TABLE (id INT, xml_col XML) INSERT INTO @xml_tab VALUES ( 5, '<?xml version="1.0" encoding="utf-8"?><doc1><row name="vahid"></row></doc1>' ) SELECT * FROM @xml_tab
<doc1> <row name="vahid" /> </doc1>
ذخیره سازی دادههایی حاوی کاراکترهای غیرمجاز XML
اطلاعات دنیای واقعی همیشه به همراه اطلاعات تک کلمهای ساده نیست. ممکن است نیاز شود انواع و اقسام حروف و تگها نیز در این بین به عنوان داده ذخیره شوند. روش حل استاندارد آن بدون نیاز به دستکاری اطلاعات ورودی، استفاده از CDATA است:
DECLARE @xml_tab TABLE (id INT, xml_col XML) INSERT INTO @xml_tab VALUES ( 5, '<person><![CDATA[ 3 > 2 ]]></person>' ) SELECT * FROM @xml_tab
<person> 3 > 2 </person>
محدودیتهای فیلدهای XML
- امکان مقایسه مستقیم را ندارند؛ بجز مقایسه با نال. البته میتوان XML را تبدیل به مثلا varchar کرد و سپس این داده رشتهای را مقایسه نمود. برای مقایسه با null توابع isnull و coalesce نیز قابل بکارگیری هستند.
- order by و group by بر روی این فیلدها پشتیبانی نمیشود.
- به عنوان ستون کلید قابل تعریف نیست.
- به صورت منحصربفرد و unique نیز قابل علامتگذاری و تعریف نیست.
- فیلدهای XML نمیتوانند دارای collate باشند.
1- اندازه گیری تعداد Transactionها در واحد زمان روی یک Database خاص در SQL Server
جهت بدست آوردن تعداد Transactionها در واحد زمان( Transactions Per Second ) روی یک Database خاص در یک سیستم عملیاتی، جهت ارتقاء سخت افزاری ، تست فشار و ... میتوانید از یک DMV با نام sys.dm_os_performance_counters به طریق زیر استفاده نمائید:declare @cntr_value bigint Select @cntr_value=cntr_value from sys.dm_os_performance_counters where instance_name='AdventureWorks' and counter_name='Write Transactions/sec' /* ایجاد یک تاخیر مثلاً یک ثانیه */ waitfor delay '00:00:01' Select cntr_value -@cntr_value from sys.dm_os_performance_counters where instance_name='AdventureWorks' and counter_name='Write Transactions/sec'
2- sys.sp_MSforeachtable
از رویههای ذخیره شده UnDocumented در SQL Server میباشد و این قابلیت را دارا است که برای هر یک از جداول موجود در یک بانک اطلاعاتی، یک رویهای را اجرا کند. برای مثال با استفاده از دستور زیر، میتوانید تعداد سطرها، اندازهی دادهها و ایندکسهای یک جدول را بدست آورید
EXEC sys.sp_MSforeachtable 'sp_spaceused ''?''';
USE [AdventureWorksDW2008R2] GO CREATE TABLE #TableSpaceUsed( [name] [nvarchar](120) NULL, [rows] [nvarchar](120) NULL, [reserved] [nvarchar](120) NULL, [data] [nvarchar](120) NULL, [index_size] [nvarchar](120) NULL, [unused] [nvarchar](120) NULL ) ON [PRIMARY] Insert Into #TableSpaceUsed EXEC sys.sp_MSforeachtable 'sp_spaceused ''?'''; Select * from #TableSpaceUsed Order by CAST([rows] as int) desc Drop table #TableSpaceUsed
چرا باید میزان دسترسی به منابع یک برنامهی وب را محدود کرد؟
فرض کنید در حال ساخت یک web API هستید که کارش ذخیره سازی لیست وظایف اشخاص است و برای مثال از یک GET /api/todos برای دریافت لیست ظایف، یک POST /api/todos برای ثبت و یک PUT /api/todos/{id} برای تغییر موارد ثبت شده، تشکیل میشود.
سؤال: چه مشکلی ممکن است به همراه این سه endpoint بروز کند؟
پاسخ: به حداقل چهار مورد زیر میتوان اشاره کرد:
- یک مهاجم سعی میکند با برنامهای که تدارک دیده، هزاران وظیفهی جدید را در چند ثانیه به سمت برنامه ارسال کند تا سبب خاتمهی سرویس آن شود.
- برنامهی ما در حین سرویس دهی، به یک سرویس ثالث نیز وابستهاست و آن سرویس ثالث، اجازهی استفادهی بیش از اندازهی از منابع خود را نمیدهد. با رسیدن تعداد زیادی درخواست به برنامهی ما تنها از طرف یک کاربر، به سقف مجاز استفادهی از آن سرویس ثالث رسیدهایم و اکنون برنامه، برای تمام کاربران آن قابل استفاده نیست.
- شخصی در حال دریافت اطلاعات تک تک کاربران است. از شماره یک شروع کرده و به همین نحو جلو میرود. برای دریافت اطلاعات کاربران، نیاز است شخص به سیستم وارد شده و اعتبارسنجی شود؛ یعنی به ازای هر درخواست، یک کوئری نیز به سمت بانک اطلاعاتی جهت بررسی وضعیت فعلی و آنی کاربر ارسال میشود. به همین جهت عدم کنترل میزان دسترسی به لیست اطلاعات کاربران، بار سنگینی را به بانک اطلاعاتی و CPU سیستم وارد میکند.
- هم اکنون چندین موتور جستجو و باتهایی نظر آنها در حال پیمایش سایت و برنامهی شما هستند که هر کدام از آنها میتوانند در حد یک مهاجم رفتار کنند.
به صورت خلاصه، همیشه استفادهی از برنامه، به آن نحوی که ما پیشبینی کردهایم، به پیش نمیرود و در آن لحظه، برنامه، در حال استفاده از CPU، حافظه و بانک اطلاعاتی به اشتراک گذاشته شدهی با تمام کاربران برنامهاست. در این حالت فقط یک کاربر مهاجم میتواند سبب از کار افتادن و یا به شدت کند شدن این برنامه شود و دسترسی سایر کاربران همزمان را مختل کند.
محدود کردن نرخ دسترسی به برنامه چیست؟
Rate limiting و یا نام دیگر آن request throttling، روشی است که توسط آن بتوان از الگوهای پیش بینی نشدهی استفادهی از برنامه جلوگیری کرد. عموما برنامههای وب، محدود کردن نرخ دسترسی را بر اساس تعداد بار درخواست انجام شدهی در یک بازهی زمانی مشخص، انجام میدهند و یا اگر کار برنامهی شما ارائهی فیلمهای ویدیویی است، شاید بخواهید میزان حجم استفاده شدهی توسط یک کاربر را کنترل کنید. در کل هدف نهایی از آن، کاهش و به حداقل رساندن روشهای آسیب زنندهی به برنامه و سیستم است؛ صرفنظر از اینکه این نحوهی استفادهی خاص، سهوی و یا عمدی باشد.
محدود کردن نرخ دسترسی را باید به چه منابعی اعمال کرد؟
پاسخ دقیق به این سؤال: «همه چیز» است! بله! همه چیز را کنترل کنید! در اینجا منظور از همه چیز، همان endpointهایی هستند که استفادهی نابجای از آنها میتوانند سبب کند شدن برنامه یا از دسترس خارج شدن آن شوند. برای مثال هر endpointای که از CPU، حافظه، دسترسی به دیسک سخت، بانک اطلاعاتی، APIهای ثالث و خارجی و امثال آن استفاده میکند، باید کنترل و محدود شود تا استفادهی ناصحیح یک کاربر از آنها، استفادهی از برنامه را برای سایر کاربران غیرممکن نکند. البته باید دقت داشت که هدف از اینکار، عصبی کردن کاربران عادی و معمولی برنامه نیست. هدف اصلی در اینجا، تشویق به استفادهی منصفانه از منابع سیستم است.
الگوریتمهای محدود کردن نرخ دسترسی
پیاده سازی ابتدایی محدود کردن نرخ دسترسی به منابع یک برنامه کار مشکلی است و در صورت استفاده از الگوریتمهای متداولی مانند تعریف یک جدول که شامل user-id، action-id و timestamp، به همراه یکبار ثبت اطلاعات به ازای هر درخواست و همچنین خواندن اطلاعات موجود است که جدول آن نیز به سرعت افزایش حجم میدهد. به همین جهت تعدادی الگوریتم بهینه برای اینکار طراحی شدهاند:
الگوریتمهای بازهی زمانی مشخص
در این روش، یک شمارشگر در یک بازهی زمانی مشخص فعال میشود و بر این مبنا است که محدودیتها اعمال خواهند شد. یک مثال آن، مجاز دانستن فقط «100 درخواست در یک دقیقه» است که نام دیگر آن «Quantized buckets / Fixed window limit» نیز هست.
برای مثال «نام هر اکشن + یک بازهی زمانی»، یک کلید دیکشنری نگهدارندهی اطلاعات محدود کردن نرخ دسترسی خواهد بود که به آن کلید، «bucket name» هم میگویند؛ مانند مقدار someaction_106062120. سپس به ازای هر درخواست رسیده، شمارشگر مرتبط با این کلید، یک واحد افزایش پیدا میکند و محدود کردن دسترسیها بر اساس مقدار این کلید صورت میگیرد. در ادامه با شروع هر بازهی زمانی جدید که در اینجا window نام دارد، یک کلید یا همان «bucket name» جدید تولید شده و مقدار متناظر با این کلید، به صفر تنظیم میشود.
اگر بجای دیکشنریهای #C از بانک اطلاعاتی Redis برای نگهداری این key/valueها استفاده شود، میتوان برای هر کدام از مقادیر آن، طول عمری را نیز مشخص کرد تا خود Redis، کار حذف خودکار اطلاعات غیرضروری را انجام دهد.
یک مشکل الگوریتمهای بازهی زمانی مشخص، غیر دقیق بودن آنها است. برای مثال فرض کنید که به ازای هر 10 ثانیه میخواهید تنها اجازهی پردازش 4 درخواست رسیده را بدهید. مشکل اینجا است که در این حالت یک کاربر میتواند 5 درخواست متوالی را بدون مشکل ارسال کند؛ 3 درخواست را در انتهای بازهی اول و دو درخواست را در ابتدای بازهی دوم:
به یک بازهی زمانی مشخص، fixed window و به انتها و ابتدای دو بازهی زمانی مشخص متوالی، sliding window میگویند. همانطور که در تصویر فوق هم مشاهده میکنید، در این اگوریتم، امکان محدود سازی دقیقی تنها در یک fixed window میسر است و نه در یک sliding window.
سؤال: آیا این مساله عدم دقت الگوریتمهای بازهی زمانی مشخص مهم است؟
پاسخ: بستگی دارد! اگر هدف شما، جلوگیری از استفادهی سهوی یا عمدی بیش از حد از منابع سیستم است، این مساله مشکل مهمی را ایجاد نمیکند. اما اگر دقت بالایی را انتظار دارید، بله، مهم است! در این حالت از الگوریتمهای «sliding window limit » بیشتر استفاده میشود که در پشت صحنه از همان روش استفادهی از چندین fixed window کوچک، کمک میگیرند.
الگوریتمهای سطل توکنها (Token buckets)
در دنیای مخابرات، از الگوریتمهای token buckets جهت کنترل میزان مصرف پهنای باند، زیاد استفاده میشود. از واژهی سطل در اینجا استفاده شده، چون عموما به همراه آب بکارگرفته میشود:
فرض کنید سطل آبی را دارید که در کف آن نشتی دارد. اگر نرخ پر کردن این سطل، با آب، از نرخ نشتی کف آن بیشتر باشد، آب از سطل، سرریز خواهد شد. به این معنا که با سرریز توکنها یا آب در این مثال، هیچ درخواست جدید دیگری پردازش نمیشود؛ تا زمانیکه مجددا سطل، به اندازهای خالی شود که بتواند توکن یا آب بیشتری را بپذیرد.
یکی از مزیتهای این روش، نداشتن مشکل عدم دقت به همراه بازههای زمانی مشخص است. در اینجا اگر تعداد درخواست زیادی به یکباره به سمت برنامه ارسال شوند، سطل پردازشی آنها سرریز شده و دیگر پردازش نمیشوند.
مزیت دیگر آنها، امکان بروز انفجاری یک ترافیک (bursts in traffic) نیز هست. برای مثال اگر قرار است سطلی با 60 توکن در دقیقه پر شود و این سطل نیز هر ثانیه یکبار تخلیه میشود، کلاینتها هنوز میتوانند 60 درخواست را در طی یک ثانیه ارسال کنند (ترافیک انفجاری) و پس از آن نرخ پردازشی، یک درخواست به ازای هر ثانیه خواهد شد.
آیا باید امکان بروز انفجار در ترافیک را داد؟
عموما در اکثر برنامهها وجود یک محدود کنندهی نرخ دسترسی کافی است. برای مثال یک محدود کنندهی نرخ دسترسی سراسری 600 درخواست در هر دقیقه، برای هر endpoint ای شاید مناسب باشد. اما گاهی از اوقات نیاز است تا امکان بروز انفجار در ترافیک (bursts) را نیز درنظر گرفت. برای مثال زمانیکه یک برنامهی موبایل شروع به کار میکند، در ابتدای راه اندازی آن تعداد زیادی درخواست، به سمت سرور ارسال میشوند و پس از آن، این سرعت کاهش پیدا میکند. در این حالت بهتر است چندین محدودیت را تعریف کرد: برای مثال امکان ارسال 10 درخواست در هر ثانیه و حداکثر 3600 درخواست در هر ساعت.
روش تشخیص کلاینتها چگونه باشد؟
تا اینجا در مورد bucket name یا کلید دیکشنری اطلاعات محدود کردن دسترسی به منابع، از روش «نام هر اکشن + یک بازهی زمانی» استفاده کردیم. به این کار «پارتیشن بندی درخواستها» هم گفته میشود. روشهای دیگری نیز برای انجام اینکار وجود دارند:
پارتیشن بندی به ازای هر
- endpoint
- آدرس IP. البته باید دقت داشت که کاربرانی که در پشت یک پروکسی قرار دارند، از یک IP آدرس اشتراکی استفاده میکنند.
- شماره کاربری. البته باید در اینجا بحث کاربران اعتبارسنجی نشده و anonymous را نیز مدنظر قرار داد.
- شمار سشن کاربر. در این حالت باید بحث ایجاد سشنهای جدید به ازای دستگاههای مختلف مورد استفادهی توسط کاربر را هم مدنظر قرار داد.
- نوع مروگر.
- هدر ویژه رسیده مانند X-Api-Token
بسته به نوع برنامه عموما از ترکیبی از موارد فوق برای پارتیشن بندی درخواستهای رسیده استفاده میشود.
درنظر گرفتن حالتهای استثنائی
هرچند همانطور که عنوان شد تمام قسمتهای برنامه باید از لحاظ میزان دسترسی محدود شوند، اما استثناءهای زیر را نیز باید درنظر گرفت:
- عموما تیم مدیریتی یا فروش برنامه، بیش از سایر کاربران، با برنامه کار میکنند.
- بیش از اندازه محدود کردن Web crawlers میتواند سبب کاهش امتیاز SEO سایت شما شود.
- گروههای خاصی از کاربران برنامه نیز میتوانند دسترسیهای بیشتری را خریداری کنند.
نحوهی خاتمهی اتصال و درخواست
اگر کاربری به حد نهایی استفادهی از منابع خود رسید، چه باید کرد؟ آیا باید صرفا درخواست او را برگشت زد یا اطلاعات بهتری را به او نمایش داد؟
برای مثال GitHub یک چنین خروجی را به همراه هدرهای ویژهای جهت مشخص سازی وضعیت محدود سازی دسترسی به منابع و علت آن، ارائه میدهد:
> HTTP/2 403 > Date: Tue, 20 Aug 2013 14:50:41 GMT > x-ratelimit-limit: 60 > x-ratelimit-remaining: 0 > x-ratelimit-used: 60 > x-ratelimit-reset: 1377013266 > { > "message": "API rate limit exceeded for xxx.xxx.xxx.xxx. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)", > "documentation_url": "https://docs.github.com/rest/overview/resources-in-the-rest-api#rate-limiting" > }
حتی یکسری از APIها از status codeهای ویژهای مانند 403 (دسترسی ممنوع)، 503 (سرویس در دسترس نیست) و یا 429 (تعداد درخواستهای زیاد) برای پاسخ دهی استفاده میکنند.
محل ذخیره سازی اطلاعات محدود سازی دسترسی به منابع کجا باشد؟
اگر محدودسازی دسترسی به منابع، جزئی از مدل تجاری برنامهی شما است، نیاز است حتما از یک بانک اطلاعاتی توزیع شده مانند Redis استفاده کرد تا بتواند اطلاعات تمام نمونههای در حال اجرای برنامه را پوشش دهد. اما اگر هدف از این محدود سازی تنها میسر ساختن دسترسی منصفانهی به منابع آن است، ذخیره سازی آنها در حافظهی همان نمونهی در حال اجرای برنامه هم کافی است.
- Lead Function:
LEAD ( scalar_expression [ ,offset ] , [ default ] ) OVER ( [ partition_by_clause ] order_by_clause )
- Scalar_expression: در Scalar_expression، نام یک فیلد یا ستون درج میشود، و مقدار برگشتی فیلد مورد نظر، به مقدار تعیین شده offset نیز بستگی دارد. خروجی Scalar_expression فقط یک مقدار است.
- offset: منظور از Offset در این Syntax همانند عملکرد Offset در Syntax مربوط به Over میباشد. یعنی هر عددی برای offset در نظر گرفته شود، بیانگر نقطه آغازین سطر بعدی یا قبلی نسبت به سطر جاری است. به بیان دیگر، عدد تعیین شده در Offset به Sql server میفهماند چه تعداد سطر را در محاسبه در نظر نگیرد.
- Default: زمانی که برای Offset مقداری را تعیین مینمایید، SQL Server به تعداد تعیین شده در Offset، سطرها را در نظر نمیگیرد، بنابراین مقدار خروجی Scalar_expression بطور پیش فرض Null در نظر گرفته میشود، چنانچه بخواهید، مقداری غیر از Null درج نمایید، میتوانید مقدار دلخواه را در قسمت Default وارد کنید.
- (OVER ( [ partition_by_clause ] order_by_clause : در بخش اول بطور کامل توضیح داده شده است.
Create Table TestLead_LAG (SalesOrderID int not null, SalesOrderDetailID int not null , OrderQty smallint not null); GO Insert Into TestLead_LAG Values (43662,49,1),(43662,50,3),(43662,51,1), (43663,52,1),(43664,53,1),(43664,54,1), (43667,77,3),(43667,78,1),(43667,79,1), (43667,80,1),(43668,81,3),(43669,110,1), (43670,111,1),(43670,112,2),(43670,113,2), (43670,114,1),(43671,115,1),(43671,116,2)
مثال:قصد داریم در هر سطر مقدار بعدی فیلد SalesOrderDetailID در فیلد دیگری به نام LeadValue نمایش دهیم، بنابراین Script زیر را ایجاد میکنیم:SELECT s.SalesOrderID,s.SalesOrderDetailID,s.OrderQty, LEAD(SalesOrderDetailID) OVER (ORDER BY SalesOrderDetailID) LeadValue FROM TestLead_LAG s WHERE SalesOrderID IN (43670, 43669, 43667, 43663) ORDER BY s.SalesOrderID,s.SalesOrderDetailID,s.OrderQtyخروجی بصورت زیر خواهد بود:
مطابق شکل، براحتی واضح است، که در هر سطر مقدار بعدی فیلد SalesOrderDetailID در فیلد LeadValue درج و نمایش داده میشود. فقط در سطر 10، چون مقدار بعدی برای فیلد SalesOrderDetailID وجود ندارد، SQL Server مقدار فیلد LeadValue را، Null در نظر میگیرد.در این مثال فقط از آرگومان Scalar_expression، استفاده کردیم، و Offset و Default را مقدار دهی ننمودیم، بنابراین SQL Server بطور پیش فرض هیچ سطری را حذف نمیکند و مقدار Default را Null در نظر میگیرد.مثال دوم: قصد داریم در هر سطر مقدار دو سطر بعدی فیلد SalesOrderDetailID را در فیلد LeadValue نمایش دهیم، و در صورت وجود نداشتن مقدار فیلد SalesOrderDetailID، مقدار پیش فرض صفر ،در فیلد LeadValue قرار دهیم،بنابراین Script آن بصورت زیر خواهد شد:SELECT s.SalesOrderID,s.SalesOrderDetailID,s.OrderQty, LEAD(SalesOrderDetailID,2,0) OVER (ORDER BY SalesOrderDetailID) LeadValue FROM TestLead_LAG s WHERE SalesOrderID IN (43670, 43669, 43667, 43663) ORDER BY s.SalesOrderID,s.SalesOrderDetailID,s.OrderQtyخروجی:
در صورت مسئله بیان کرده بودیم، در هر سطر،مقدار فیلد SalesOrderDetailID دو سطر بعدی، را نمایش دهیم، بنابراین مقداری که برای Offset در نظر میگیریم، برابر دو خواهد بود، سپس گفته بودیم، چنانچه در هر سطر مقدار فیلد SalesOrderDetailID وجود نداشت،بجای مقدار پیش فرض Null،از مقدار صفر استفاده شود، بنابراین به Default مقدار صفر را نسبت دادیم.LEAD(SalesOrderDetailID,2,0)در شکل، مطابق صورت مسئله، مقدار فیلد LeadValue سطر اول برابر است با 78،به بیان سادهتر برای بدست آوردن مقدار فیلد LaedValue هر سطر، میبایست هر سطر را به علاوه 2 (Offset) نماییم، تا سطر بعدی بدست آید، سپس مقدار SalesOrderDetailID را در فیلد LeadValue قرار میدهیم.به سطر 9 و 10 توجه نمایید، که مقدار فیلد LeadValue آنها برابر با صفر است، واضح است، سطر 10 + 2 برابر است با 12( 10+2=12 )، چنین سطری در خروجی نداریم، بنابراین بطور پیش فرض مقدار LeadVaule توسط Sql Server برابر Null در نظر گرفته میشود، اما نمیخواستیم، که این مقدار Null باشد، بنابراین به آرگومان Default مقدار صفر را نسبت دادیم، تا SQL Server ، به جای استفاده از Null، مقدار در نظر گرفته شده صفر را استفاده نماید.اگر چنین فانکشنی وجود نداشت، برای شبیه سازی آن میبایست از Join روی خود جدول استفاده مینمودیم، و یکسری محاسابت دیگر، که کار را سخت مینمود، مثال دوم را با Script زیر میتوان شبیه سازی نمود:WITH cteLead AS ( SELECT SalesOrderID,SalesOrderDetailID,OrderQty, ROW_NUMBER() OVER (ORDER BY SalesOrderDetailID) AS sn FROM TestLead_LAG WHERE SalesOrderID IN (43670, 43669, 43667, 43663) ) SELECT m.SalesOrderID, m.SalesOrderDetailID, m.OrderQty, case when sLead.SalesOrderDetailID is null Then 0 Else sLead.SalesOrderDetailID END as leadvalue FROM cteLead AS m LEFT OUTER JOIN cteLead AS sLead ON sLead.sn = m.sn+2 ORDER BY m.SalesOrderID, m.SalesOrderDetailID, m.OrderQtyجدول موقتی ایجاد نمودیم، که ROW_Number را در آن اضافه کردیم، سپس جدول ایجاد شده را با خود Join کردیم، و گفتیم، که مقدار فیلدLeadValue هر سطر برابر است با مقدار فیلد SalesOrderDetailID دو سطر بعد از آن. و با Case نیز مقدار پیش فرض را صفر در نظر گرفتیم.
- LAG Function:
این فانکشن نیز در SQL Server 2012 ارائه شده است، و امکان دسترسی، به Dataهای سطر قبلی نسبت به سطر جاری را در نتیجه یک پرس و جو (Query)، ارائه میدهد. بدون آنکه از Self-join استفاده نمایید،Syntax آن شبیه به فانکشن Lead میباشد و بصورت زیر است:LAG (scalar_expression [,offset] [,default]) OVER ( [ partition_by_clause ] order_by_clause )Syntax مربوط به فانکشن LAG را شرح نمیدهم، بدلیل آنکه شبیه به فانکشن Lead میباشد، فقط تفاوت آن در Offset است، Offset در فانکشن LAG روی سطرهای ماقبل سطر جاری اعمال میگردد.مثال دوم را برای حالت LAG Function شبیه سازی مینماییم:SELECT s.SalesOrderID,s.SalesOrderDetailID,s.OrderQty, LAG(SalesOrderDetailID,2,0) OVER (ORDER BY SalesOrderDetailID) LAGValue FROM TestLead_LAG s WHERE SalesOrderID IN (43670, 43669, 43667, 43663) ORDER BY s.SalesOrderID,s.SalesOrderDetailID,s.OrderQty goخروجی :
همانطور که گفتیم، LAG Function عکس LEAD Function میباشد. یعنی مقدار فیلد LAGValue سطر جاری برابر است با مقدار SalesOrderDetailID دو سطر ما قبل خود.مقدار فیلد LAGValue دو سطر اول و دوم نیز برابر صفر است، چون دو سطر ماقبل آنها وجود ندارد، و مقدار صفر نیز بدلیل این است که Default را برابر صفر در نظر گرفته بودیم.مثال: در این مثال از Laed Function و LAG Function بطور همزمان استفاده میکنیم، با این تفاوت، که از گروه بندی نیز استفاده شده است:Script زیر را اجرا نمایید:SELECT s.SalesOrderID,s.SalesOrderDetailID,s.OrderQty, Lead(SalesOrderDetailID) OVER (PARTITION BY SalesOrderID ORDER BY SalesOrderDetailID) LeadValue, LAG(SalesOrderDetailID) OVER (PARTITION BY SalesOrderID ORDER BY SalesOrderDetailID) LAGValue FROM TestLead_LAG s WHERE SalesOrderID IN (43670, 43669, 43667, 43663) ORDER BY s.SalesOrderID,s.SalesOrderDetailID,s.OrderQty goخروجی:با بررسی هایی که در مثالهای قبل نمودیم،خروجی زیر را میتوان براحتی تشخیص داد، و توضیح بیشتری نمیدهم.موفق باشید.