نظرات مطالب
شروع به کار با AngularJS 2.0 و TypeScript - قسمت اول - نصب پیشنیازها
نیاز به یک Gulp Task دارد تا تمام فایل‌های پروژه به همراه فایل‌های AngularJS 2.0 یکی شوند؛ به همراه uglify و minify خودکار: «شروع به کار با AngularJS 2.0 و TypeScript - قسمت دوازدهم - توزیع برنامه»
 
مطالب
شروع به کار با AngularJS 2.0 و TypeScript - قسمت هفتم - سرویس‌ها و تزریق وابستگی‌ها
یک سرویس در AngularJS 2.0، کلاسی است با هدفی محدود و مشخص. این سرویس‌ها مستقل از کامپوننتی خاص هستند و هدف آن‌ها، به اشتراک گذاشتن اطلاعات و یا منطقی بین کامپوننت‌های مختلف می‌باشد. همچنین از آن‌ها برای کپسوله سازی تعاملات خارجی، مانند دسترسی به داده‌ها نیز استفاده می‌شود.


نگاهی به نحوه‌ی عملکرد سرویس‌ها و تزریق وابستگی‌ها در AngularJS 2.0

فرض کنید کلاس سرویسی، به نحو ذیل تعریف شده‌است:
 export class MyService {}
این کلاس، خارج از کلاس متناظر با یک کامپوننت قرار داد. بنابراین برای استفاده‌ی از آن، می‌توان آن‌را به صورت مستقیم، داخل کلاسی که به آن نیاز دارد، وهله سازی/نمونه سازی نمود و استفاده کرد:
 let svc = new MyService();
هر چند این روش کار می‌کند، اما نمونه‌ی ایجاد شده، سطح دسترسی محلی، در این کلاس دارد و در خارج آن قابل دسترسی نیست. بنابراین نمی‌توان از آن برای به اشتراک گذاشتن اطلاعات و منابع، بین کامپوننت‌های مختلف استفاده کرد.
همچنین در این حالت، mocking این سرویس برای نوشتن unit tests نیز مشکل می‌باشد.

راه بهتر و توصیه شده‌ی در اینجا، ثبت و معرفی این سرویس‌ها به AngularJS 2.0 است. سپس AngularJS 2.0 به ازای هر کلاس سرویس معرفی شده‌ی به آن، یک وهله/نمونه را ایجاد می‌کند. بنابراین طول عمر سرویس‌های ایجاد شده‌ی در این حالت، singleton است (یکبار ایجاد شده و تا پایان طول عمر برنامه زنده نگه داشته می‌شوند).
پس از آن می‌توان از تزریق کننده‌های توکار AngularJS 2.0، جهت تزریق وهله‌های این سرویس‌ها استفاده کرد.
اکنون اگر کلاسی، نیاز به این سرویس داشته باشد، نیاز خود را به صورت یک وابستگی تعریف شده‌ی در سازنده‌ی کلاس اعلام می‌کند:
 constructor(private _myService: MyService){}
در این حالت زمانیکه کلاس کامپوننت، برای اولین بار وهله سازی می‌شود، سرویس مورد نیاز آن نیز توسط تزریق کننده‌ی توکار AngularJS 2.0، در اختیارش قرار می‌گیرد.
به این فرآیند اصطلاحا dependency injection و یا تزریق وابستگی‌ها می‌گویند. در فرآیند تزریق وابستگی‌ها، یک کلاس، وهله‌های کلاس‌های دیگر مورد نیاز خودش را بجای وهله سازی مستقیم، از یک تزریق کننده دریافت می‌کند. بنابراین بجای نوشتن newها در کلاس جاری، آن‌ها را به صورت وابستگی‌هایی در سازنده‌ی کلاس تعریف می‌کنیم تا توسط AngularJS 2.0 تامین شوند.

با توجه به اینکه طول عمر این وابستگی‌ها singleton است و این طول عمر توسط AngularJS 2.0 مدیریت می‌شود، اطلاعات وهله‌های سرویس‌های مختلف و تغییرات صورت گرفته‌ی در آن‌ها، بین تمام کامپوننت‌ها به صورت یکسانی به اشتراک گذاشته می‌شوند.
به علاوه اکنون امکان mocking سرویس‌ها با توجه به عدم وهله سازی آن‌ها در داخل کلاس‌ها به صورت مستقیم، ساده‌تر از قبل میسر است.


مراحل ساخت یک سرویس در AngularJS 2.0

ساخت یک سرویس در AngularJS 2.0، با ایجاد یک کلاس جدید شروع می‌شود. سپس متادیتای آن افزوده شده و در آخر موارد مورد نیاز آن import خواهند شد. با این موارد پیشتر در حین ساختن یک کامپوننت جدید و یا یک Pipe جدید آشنا شده‌اید و این طراحی یک دست را در سراسر AngularJS 2.0 می‌توان مشاهده کرد.
اولین سرویس خود را با افزودن فایل جدید product.service.ts به پوشه‌ی app\products آغاز می‌کنیم؛ با این محتوا:
import { Injectable } from 'angular2/core';
import { IProduct } from './product';
 
@Injectable()
export class ProductService {
 
    getProducts(): IProduct[] {
        return [
            {
                "productId": 2,
                "productName": "Garden Cart",
                "productCode": "GDN-0023",
                "releaseDate": "March 18, 2016",
                "description": "15 gallon capacity rolling garden cart",
                "price": 32.99,
                "starRating": 4.2,
                "imageUrl": "app/assets/images/garden_cart.png"
            },
            {
                "productId": 5,
                "productName": "Hammer",
                "productCode": "TBX-0048",
                "releaseDate": "May 21, 2016",
                "description": "Curved claw steel hammer",
                "price": 8.9,
                "starRating": 4.8,
                "imageUrl": "app/assets/images/rejon_Hammer.png"
            }
        ];
    }
}
نام کلاس سرویس نیز pascal case است و بهتر است به کلمه‌ی Service ختم شود.
همانند سایر ماژول‌های تعریف شده‌، در اینجا نیز باید کلاس تعریف شده export شود تا در قسمت‌های دیگر قابل استفاده و دسترسی گردد.
سپس در این سرویس، یک متد برای بازگشت لیست محصولات ایجاد شده‌است.
در ادامه یک decorator جدید به نام ()Injectable@  به بالای این کلاس اضافه شده‌است. این متادیتا است که مشخص می‌کند کلاس جاری، یک سرویس AngularJS 2.0 است.
البته باید دقت داشت که این مزین کننده تنها زمانی نیاز است حتما قید شود که کلاس تعریف شده، دارای وابستگی‌های تزریق شده‌ای باشد. اما توصیه شده‌است که بهتر است هر کلاس سرویسی (حتی اگر دارای وابستگی‌های تزریق شده‌ای هم نبود) به این decorator ویژه، مزین شود تا بتوان طراحی یک دستی را در سراسر برنامه شاهد بود.
در آخر هم موارد مورد نیاز، import می‌شوند. برای مثال Injectable در ماژول angular2/core تعریف شده‌است.

هدف از تعریف این سرویس، دور کردن وظیفه‌ی تامین داده، از کلاس کامپوننت لیست محصولات است؛ جهت رسیدن به یک طراحی SOLID.
در قسمت بعدی این سری، این لیست را بجای یک آرایه‌ی از پیش تعریف شده، از یک سرور HTTP دریافت خواهیم کرد.


ثبت و معرفی سرویس جدید ProductService به AngularJS 2.0 Injector

مرحله‌ی اول استفاده از سرویس‌های تعریف شده، ثبت و معرفی آن‌ها به AngularJS 2.0 Injector است. سپس این Injector است که تک وهله‌ی سرویس ثبت شده‌ی در آن‌را در اختیار هر کامپوننتی که آن‌را درخواست کند، قرار می‌دهد.
مرحله‌ی ثبت این سرویس، معرفی نام این کلاس، به خاصیتی آرایه‌ای، به نام providers است که یکی از خواص decorator ویژه‌ی Component است. بدیهی است هر کامپوننتی که در برنامه وجود داشته باشد، توانایی ثبت این سرویس را نیز دارد؛ اما باید از کدامیک استفاده کرد؟
اگر سرویس خود را در کامپوننت لیست محصولات رجیستر کنیم، تک وهله‌ی این سرویس تنها در این کامپوننت و زیر کامپوننت‌های آن در دسترس خواهند بود و اگر این سرویس را در بیش از یک کامپوننت ثبت کنیم، آنگاه دیگر هدف اصلی طول عمر singleton یک سرویس مفهومی نداشته و برنامه هم اکنون دارای چندین وهله از سرویس تعریف شده‌ی ما می‌گردد و دیگر نمی‌توان اطلاعات یکسانی را بین کامپوننت‌ها به اشتراک گذاشت.
بنابراین توصیه شده‌است که از خاصیت providers کامپوننت‌های غیر ریشه‌ای، صرفنظر کرده و سرویس‌های خود را تنها در بالاترین سطح کامپوننت‌های تعریف شده، یعنی در فایل app.component.ts ثبت و معرفی کنید. به این ترتیب تک وهله‌ی ایجاد شده‌ی در اینجا، در این کامپوننت ریشه‌ای و تمام زیر کامپوننت‌های آن (یعنی تمام کامپوننت‌های دیگر برنامه) به صورت یکسانی در دسترس قرار می‌گیرد.
به همین جهت فایل app.component.ts را گشوده و تغییرات ذیل را به آن اعمال کنید:
import { Component } from 'angular2/core';
import { ProductListComponent } from './products/product-list.component';
import { ProductService } from './products/product.service';
 
@Component({
    selector: 'pm-app',
    template:`
    <div><h1>{{pageTitle}}</h1>
        <pm-products></pm-products>
    </div>
    `,
    directives: [ProductListComponent],
    providers: [ProductService]
})
export class AppComponent {
    pageTitle: string = "DNT AngularJS 2.0 APP";
}
در اینجا دو تغییر جدید صورت گرفته‌اند:
الف) خاصیت providers که آرایه‌ای از سرویس‌ها را قبول می‌کند، با ProductService مقدار دهی شده‌است.
ب) در ابتدای فایل، ProductService، از ماژول آن import گردیده‌است.


تزریق سرویس‌ها به کامپوننت‌ها

تا اینجا یک سرویس جدید را ایجاد کردیم و سپس آن‌را به AngularJS 2.0 Injector معرفی نمودیم. اکنون نوبت به استفاده و تزریق آن، به کلاسی است که به این وابستگی نیاز دارد. در TypeScript، تزریق وابستگی‌ها در سازنده‌ی یک کلاس صورت می‌گیرند. هر کلاس، دارای متد سازنده‌ای است که در زمان وهله سازی آن، اجرا می‌شود. اگر نیاز به تزریق وابستگی‌ها باشد، تعریف این سازنده به صورت صریح، ضروری است. باید دقت داشت که هدف اصلی از متد سازنده، آغاز و مقدار دهی متغیرها و وابستگی‌های مورد نیاز یک کلاس است و باید تا حد امکان از منطق‌های طولانی عاری باشد.
در ادامه فایل product-list.component.ts را گشوده و سپس سازنده‌ی ذیل را به آن اضافه کنید:
import { ProductService } from './product.service';
export class ProductListComponent implements OnInit {
    pageTitle: string = 'Product List';
    imageWidth: number = 50;
    imageMargin: number = 2;
    showImage: boolean = false;
    listFilter: string = 'cart';
 
    constructor(private _productService: ProductService) {
    }
سازنده‌ی کلاس عموما پس از لیست خواص آن کلاس تعریف می‌شود و پیش از تعاریف سایر متدهای آن.
روش خلاصه شده‌ای که در اینجا جهت تعریف سازنده‌ی کلاس و متغیر تعریف شده‌ی در آن بکار گرفته شده، معادل قطعه کد متداول ذیل است و هر دو حالت ذکر شده، در TypeScript یکی می‌باشند:
private _productService: ProductService;
constructor(productService: ProductService) {
   _productService = productService;
}
در اینجا سرویس مورد نیاز را به صورت یک متغیر private در سازنده‌ی کلاس ذکر می‌کنیم (مرسوم است متغیرهای private با _ شروع شوند). همچنین این سرویس باید در لیست import ابتدای ماژول جاری نیز ذکر شود.
این وابستگی در اولین باری که کلاس کامپوننت، توسط AngularJS 2.0 وهله سازی می‌شود، از لیست providers ثبت شده‌ی در کامپوننت ریشه‌ی سایت، تامین خواهد شد.
اکنون نوبت به استفاده‌ی از این سرویس تزریق شده‌است. به همین جهت ابتدا لیست عناصر آرایه‌ی خاصیت products را حذف می‌کنیم (برای اینکه قرار است این سرویس، کار تامین اطلاعات را انجام دهد و نه کلاس کامپوننت).
 products: IProduct[];
خوب، در ادامه، کدهای مقدار دهی آرایه‌ی products را از سرویس دریافتی، در کجا قرار دهیم؟ شاید عنوان کنید که در همین متد سازنده‌ی کلاس نیز می‌توان این‌کار را انجام داد.
 this.products = _productService.getProducts();
هر چند در مثال جاری که از یک آرایه‌ی از پیش تعریف شده، برای این مقصود استفاده می‌شود، این مقدار دهی مشکلی را ایجاد نخواهد کرد، اما در قسمت بعدی که می‌خواهیم آن‌را از سرور دریافت کنیم، فراخوانی متد getProducts، اندکی زمانبر خواهد بود. بنابراین رویه‌ی کلی این است که کدهای زمانبر، نباید در سازنده‌ی یک کلاس قرار گیرند؛ چون سبب تاخیر در بارگذاری تمام قسمت‌های آن می‌شوند.
به همین جهت روش صحیح انجام این مقدار دهی، با پیاده سازی life cycle hook ویژه‌ای به نام OnInit است که در قسمت پنجم آن‌را معرفی کردیم:
export class ProductListComponent implements OnInit {
products: IProduct[];

constructor(private _productService: ProductService) {
}

ngOnInit(): void {
    //console.log('In OnInit');
    this.products = this._productService.getProducts();
}
هر نوع عملیات آغازین مقدار دهی متغیرها و خواص کامپوننت‌ها باید در ngOnInit مربوط به هوک OnInit انجام شود که نمونه‌ای از آن‌را در کدهای فوق ملاحظه می‌کنید.
در اینجا اکنون خاصیت products عاری است از ذکر صریح عناصر تشکیل دهنده‌ی آن. سپس وابستگی مورد نیاز، در سازنده‌ی کلاس تزریق شده‌است و در آخر، در رویداد چرخه‌ی حیات ngOnInit، با استفاده از این وابستگی تزریقی، لیست محصولات دریافت و به خاصیت عمومی products نسبت داده شده‌است.

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


کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید: MVC5Angular2.part7.zip


خلاصه‌ی بحث
فرآیند کلی تعریف یک سرویس AngularJS 2.0، تفاوتی با ساخت یک کامپوننت یا Pipe سفارشی ندارد. پس از تعریف کلاسی که نام آن ختم شده‌ی به Service است، آن‌را مزین به ()Injectable@ می‌کنیم. سپس این سرویس را در بالاترین سطح کامپوننت‌های موجود یا همان کامپوننت ریشه‌ی سایت، ثبت و معرفی می‌کنیم؛ تا تنها یک وهله از آن توسط AngularJS 2.0 Injector ایجاد شده و در اختیار تمام کامپوننت‌های برنامه قرار گیرد. البته اگر این سرویس تنها در یک کامپوننت استفاده می‌شود و قصد به اشتراک گذاری اطلاعات آن‌را نداریم، می‌توان سطح سلسله مراتب دسترسی به آن‌را نیز کاهش داد. برای مثال این سرویس را در لیست providers همان کامپوننت ویژه، ثبت و معرفی کرد. به این ترتیب تنها این کامپوننت خاص و فرزندان آن دسترسی به امکانات سرویس مدنظر را می‌یابند و نه تمام کامپوننت‌های دیگر تعریف شده‌ی در برنامه.
در ادامه هر کلاسی که به این سرویس نیاز دارد (با توجه به سلسه مراتب دسترسی ذکر شده)، تنها کافی است در سازنده‌ی خود، این وابستگی را اعلام کند تا توسط AngularJS 2.0 Injector تامین گردد.
مطالب دوره‌ها
پشتیبانی از XML Schema در SQL Server
XML Schema چیست؟

XML Schema معرف ساختار، نوع داده‌ها و المان‌های یک سند XML است. البته باید درنظر داشت که تعریف XML Schema کاملا اختیاری است و اگر تعریف شود مزیت اعتبارسنجی داده‌های در حال ذخیره سازی در بانک اطلاعاتی را به صورت خودکار به همراه خواهد داشت. در این حالت به نوع داده‌ای XML دارای اسکیما، typed XML و به نوع بدون اسکیما، untyped XML گفته می‌شود.
به یک نوع XML، چندین اسکیمای مختلف را می‌توان نسبت داد و به آن XML schema collection نیز می‌گویند.



XML schema collections پیش فرض و سیستمی

تعدادی XML Schema پیش فرض در SQL Server تعریف شده‌اند که به آن‌ها sys schema collections گفته می‌شود.
 Prefix - Namespace
xml = http://www.w3.org/XML/1998/namespace
xs = http://www.w3.org/2001/XMLSchema
xsi = http://www.w3.org/2001/XMLSchema-instance
fn = http://www.w3.org/2004/07/xpath-functions
sqltypes = http://schemas.microsoft.com/sqlserver/2004/sqltypes
xdt = http://www.w3.org/2004/07/xpath-datatypes
(no prefix) = urn:schemas-microsoft-com:xml-sql
(no prefix) = http://schemas.microsoft.com/sqlserver/2004/SOAP
در اینجا پیشوندها و فضاهای نام sys schema collections را ملاحظه می‌کنید. از این اسکیماها برای تعاریف strongly typed امکانات موجود در SQL Server کمک گرفته شده‌است.
اگر علاقمند باشید تا این تعاریف را مشاهده کنید به مسیر Program Files\Microsoft SQL Server\version\Tools\Binn\schemas\sqlserver در جایی که SQL Server نصب شده‌است مراجعه نمائید. برای مثال در مسیر Tools\Binn\schemas\sqlserver\2006\11\events فایل events.xsd قابل مشاهده است و یا در مسیر Tools\Binn\schemas\sqlserver\2004\07 اسکیمای ابزارهای query processor و  show plan قابل بررسی می‌باشد.
مهم‌ترین آن‌ها را در پوشه Tools\Binn\schemas\sqlserver\2004\sqltypes در فایل sqltypes.xsd می‌توانید ملاحظه کنید. اگر به محتوای آن دقت کنید، قسمتی از آن به شرح ذیل است:
  <xsd:simpleType name="char">
    <xsd:restriction base="xsd:string"/>
  </xsd:simpleType>
  <xsd:simpleType name="nchar">
    <xsd:restriction base="xsd:string"/>
  </xsd:simpleType>
  <xsd:simpleType name="varchar">
    <xsd:restriction base="xsd:string"/>
  </xsd:simpleType>
  <xsd:simpleType name="nvarchar">
    <xsd:restriction base="xsd:string"/>
  </xsd:simpleType>
  <xsd:simpleType name="text">
    <xsd:restriction base="xsd:string"/>
  </xsd:simpleType>
  <xsd:simpleType name="ntext">
    <xsd:restriction base="xsd:string"/>
  </xsd:simpleType>
در اینجا نوع‌های توکار char تا ntext به xsd:string نگاشت شده‌اند و برای اعتبارسنجی datetime و نگاشت آن، از الگوی ذیل استفاده می‌شود؛ به همراه حداقل و حداکثر قابل تعریف:
  <xsd:simpleType name="datetime">
    <xsd:restriction base="xsd:dateTime">
      <xsd:pattern value="((000[1-9])|(00[1-9][0-9])|(0[1-9][0-9]{2})|([1-9][0-9]{3}))-((0[1-9])|(1[012]))-((0[1-9])|([12][0-9])|(3[01]))T(([01][0-9])|(2[0-3]))(:[0-5][0-9]){2}(\.[0-9]{2}[037])?"/>
      <xsd:maxInclusive value="9999-12-31T23:59:59.997"/>
      <xsd:minInclusive value="1753-01-01T00:00:00.000"/>
    </xsd:restriction>
  </xsd:simpleType>
ادیتور SQL Server managment studio به خوبی، گشودن، ایجاد و یا ویرایش فایل‌هایی با پسوند xsd را پشتیبانی می‌کند.



تعریف XML Schema و استفاده از آن جهت تعریف یک strongly typed XML

XML Schema مورد استفاده در SQL Server حتما باید در بانک اطلاعاتی ذخیره شود و برای خواندن آن، برای مثال از فایل سیستم استفاده نخواهد شد.
CREATE XML SCHEMA COLLECTION invcol AS
'<xs:schema ... targetNamespace="urn:invoices">
...
</xs:schema>
'

CREATE TABLE Invoices(
id int IDENTITY PRIMARY KEY,
invoice XML(invcol)
)
در اینجا نحوه‌ی تعریف کلی یک XML Schema collection و سپس انتساب آن‌را به یک ستون XML ملاحظه می‌کنید. ستون invoice که از نوع XML تعریف شده، ارجاعی را به اسکیمای تعریف شده دارد.
در ادامه نحوه‌ی تعریف یک اسکیمای نمونه قابل مشاهده است:
CREATE XML SCHEMA COLLECTION geocol AS
'<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="urn:geo"
           elementFormDefault="qualified"
           xmlns:tns="urn:geo">
  <xs:simpleType name="dim">
    <xs:restriction base="xs:int" />
  </xs:simpleType>
  <xs:complexType name="Point">
    <xs:sequence>
      <xs:element name="X" type="tns:dim"  minOccurs="0" maxOccurs="unbounded" />
      <xs:element name="Y" type="tns:dim"  minOccurs="0" maxOccurs="unbounded" />
    </xs:sequence>
  </xs:complexType>
  <xs:element name="Point" type="tns:Point" />
</xs:schema>'
در این اسکیما، یک نوع ساده به نام dim تعریف شده‌است که محدودیت آن، ورود اعداد صحیح می‌باشد. همچنین امکان تعریف نوع‌های پیچیده نیز در اینجا وجود دارد. برای مثال نوع پچیده Point دارای دو المان X و Y از نوع dim در ادامه تعریف شده‌است. المانی که نهایتا بر این اساس در XML ظاهر خواهد شد توسط xs:element تعریف شده‌است.
اکنون برای آزمایش اسکیمای تعریف شده، جدول geo_tab را به نحو ذیل تعریف می‌کنیم و سپس سعی در insert دو رکورد در آن خواهیم کرد:
 declare @geo_tab table(
 id int identity primary key,
 point xml(content geocol)
)
 
insert into @geo_tab values('<Point xmlns="urn:geo"><X>10</X><Y>20</Y></Point>')
insert into @geo_tab values('<Point xmlns="urn:geo"><X>10</X><Y>test</Y></Point>')
در اینجا اگر دقت کنید، برای تعریف نام اسکیمای مورد استفاده، واژه content نیز ذکر شده‌است. Content مقدار پیش فرض است و در آن پذیرش XML Fragments یا محتوای XML ایی با بیش از یک Root element مجاز است. حالت دیگر آن document است که تنها یک Root element را می‌پذیرد.
در این مثال، insert اول با موفقیت انجام خواهد شد؛ اما insert دوم با خطای ذیل متوقف می‌شود:
 XML Validation: Invalid simple type value: 'test'. Location: /*:Point[1]/*:Y[1]
همانطور که ملاحظه می‌کنید، چون در insert دوم، در المان عددی Y، مقدار test وارد شده‌است و تطابقی با اسکیمای تعریف شده ندارد، insert آن مجاز نخواهد بود.



یافتن محل ذخیره سازی اطلاعات اسکیما در SQL Server

اگر علاقمند باشید تا با محل ذخیره سازی اطلاعات اسکیما، نوع‌های تعریف شده و حتی محل استفاده از آن‌ها در بانک‌های اطلاعاتی مختلف موجود آشنا شوید و گزارشی از آن‌ها تهیه کنید، می‌توانید از کوئری‌های ذیل استفاده نمائید:
 select * from sys.xml_schema_collections
select * from sys.xml_schema_namespaces
select * from sys.xml_schema_elements
select * from sys.xml_schema_attributes
select * from sys.xml_schema_types
select * from sys.column_xml_schema_collection_usages
select * from sys.parameter_xml_schema_collection_usages
باید دقت داشت زمانیکه یک schema در حال استفاده است (یک رکورد ثبت شده مقید به آن تعریف شده باشد)، امکان drop آن نخواهد بود. حتما باید اطلاعات و ستون مرتبط، ارجاعی را به schema نداشته باشند تا بتوان آن schema را حذف کرد.
محتوای اسکیمای ذخیره شده به شکل xsd تعریف شده، ذخیره سازی نمی‌شود. بلکه اطلاعات آن تجزیه شده و سپس در جداول سیستمی SQL Server ذخیره می‌گردند. هدف از اینکار، بالا بردن سرعت اعتبارسنجی typed XMLها است.
بنابراین بدیهی است در این حالت اطلاعاتی مانند commnets موجود در xsd تهیه شده در بانک اطلاعاتی ذخیره نمی‌گردند.
برای بازیابی اطلاعات اسکیمای ذخیره شده می‌توان از متد xml_schema_namespace استفاده کرد:
 declare @x xml
select @x = xml_schema_namespace(N'dbo', N'geocol')
print convert(varchar(max), @x)
برای تعریف و یا تغییر یک XML Schema نیاز به دسترسی مدیریتی یا dbo است (به صورت پیش فرض). همچنین برای استفاده از Schema تعریف شده، کاربر متصل به SQL Server باید دسترسی Execute و References نیز داشته باشد.



نحوه‌ی ویرایش یک schema collection موجود

چند نکته:
- امکان alter یک schema collection وجود دارد.
- می‌توان یک schema جدید را به collection موجود افزود.
- امکان افزودن (و نه تغییر) نوع‌های یک schema موجود، میسر است.
- امکان drop یک اسکیما از collection موجودی وجود ندارد. باید کل collection را drop کرد و سپس آن‌را تعریف نمود.
- جداولی با فیلدهای nvarchar را می‌توان به فیلدهای XML تبدیل کرد و برعکس.
- امکان تغییر یک فیلد XML به حالت untyped و برعکس وجود دارد.

فرض کنید که می‌خواهیم اسکیمای متناظر با یک ستون XML را تغییر دهیم. ابتدا باید آن ستون XML ایی را Alter کرده و قید اسکیمای آن‌را برداریم. سپس باید اسکیمای موجود را drop و مجددا ایجاد کرد. همانطور که پیشتر ذکر شد، اگر اسکیمایی در حال استفاده باشد، قابل drop نیست. در ادامه مجددا باید ستون XML ایی را تغییر داده و اسکیمای آن‌را معرفی کرد.
روش دوم مدیریت این مساله، اجازه دادن به حضور بیش از یک اسکیما در مجموعه است. به عبارتی نگارش‌بندی اسکیما که به نحو ذیل قابل انجام است:
 alter XML SCHEMA COLLECTION geocol add @x
در اینجا به collection موجود، یک اسکیمای جدید (برای مثال نگارش دوم اسکیمای فعلی) اضافه می‌شود. در این حالت geocol، هر دو نوع اسکیمای موجود را پشتیبانی خواهد کرد.



نحوه‌ی import یک فایل xsd و ذخیره آن به صورت اسکیما

اگر بخواهیم یک فایل xsd موجود را به عنوان xsd معرفی کنیم می‌توان از دستورات ذیل کمک گرفت:
 declare @x xml
set @x = (select * from openrowset(bulk 'c:\path\file.xsd', single_blob) as x)
CREATE XML SCHEMA COLLECTION geocol2 AS @x
در اینجا به کمک openrowset فایل xsd موجود، در یک متغیر xml بارگذاری شده و سپس در دستور ایجاد یک اسکیما کالکشن جدید استفاده می‌شود.
از openrowset برای خواندن یک فایل xml موجود، جهت insert محتوای آن در بانک اطلاعاتی نیز می‌توان استفاده کرد.



محدودیت‌های XML Schema در SQL Server

تمام استاندارد XML Schema در SQL Server پشتیبانی نمی‌شود و همچنین این مورد از نگارشی به نگارشی دیگر نیز ممکن است تغییر یافته و بهبود یابد. برای مثال در SQL Server 2005 از xs:any پشتیبانی نمی‌شود اما در SQL Server 2008 این محدودیت برطرف شده‌است. همچنین مواردی مانند xs:include، xs:redefine، xs:notation، xs:key، xs:keyref و xs:unique در SQL Server پشتیبانی نمی‌شوند.



یک نکته‌ی تکمیلی

برنامه‌ای به نام xsd.exe به همراه Visual Studio ارائه می‌شود که قادر است به صورت خودکار از یک فایل XML موجود، XML Schema تولید کند. اطلاعات بیشتر 
نظرات مطالب
سفارشی سازی ASP.NET Core Identity - قسمت اول - موجودیت‌های پایه و DbContext برنامه
- یک نمونه استفاده‌ی‌از آن خاصیت public، در متد GetLastUserPasswordChangeDateAsync هست که از GetShadowPropertyValue استفاده می‌کند.
- برای سایر حالات از نکات مطرح شده‌ی در مطلب خواص سایه‌ای یا Shadow properties استفاده کنید و بجای ذکر رشته‌ها، می‌توان از خواص public static readonly string این کلاس در متد EF.Property استفاده کرد تا Refactoring friendly شود (هدف اصلی این خواص عمومی).
var items = context.Persons
             .Where(x => EF.Property<DateTimeOffset?>(x, AuditableShadowProperties.CreatedDateTime) <= DateTimeOffset.UtcNow).ToList();
مطالب دوره‌ها
لیست ها و آرایه ها در #F
برای تعریف لیست در #F فقط کافیست از [] و برای جداسازی آیتم‌های موجود در لیست از عملگر :: (بخوانید cons) استفاده کنید. #F از لیست‌های خالی نیز پشتیبانی می‌کند. به مثال هایی از این دست توجه کنید

#1 let emptyList = []
#2 let oneItem = "one " :: []
#3 let twoItem = "one " :: "two " :: []
#1 تعریف یک لیست خالی
#2 تعریف یک لیست به همراه یک آیتم
#3 تعریف یک لیست به همراه دو آیتم
قبول دارم که دستورالعمل بالا برای مقدار دهی اولیه به لیست کمی طولانی و سخت است. برای همین می‌تونید از روش زیر هم استفاده کنید.
let shortHand = ["apples "; "pears"]
*کد بالا یک لیست با دو آیتم که از نوع رشته ای هستند تولید خواهد کرد.
می‌تونید از عملگر @ برای پیوستن دو لیست به هم نیز استفاده کنید.
let twoLists = ["one, "; "two, "] @ ["buckle "; "my "; "shoe "]

نکته : تمام آیتم‌های موجود در لیست باید از یک نوع باشند. بعنی امکان تعریف لیستی که دارای آیتم هایی با datatype‌های متفاوت باشد باعث تولید خطای کامپایلری می‌شود. اما اگر نیاز به لیستی دارید که باید چند datatype رو هم پوشش دهد می‌تونید از object‌ها استفاده کنید.
let objList = [box 1; box 2.0; box "three"]
در بالا یک لیست از object‌ها رو تعریف کرده ایم. فقط دقت کنید برای اینکه آیتم‌های موجود در لیست رو تبدیل به object کنیم از دستور box قبل از هر آیتم استفاده کردیم.

 در هنگام استفاده از عملگر‌ها @ و :: مقدار لیست تغییر نمی‌کند بلکه یک لیست جدید تولید خواهد شد.
#1 let one = ["one "]
#2 let two = "two " :: one
#3 let three = "three " :: two
#4 let rightWayRound = List.rev three

#5 let main() =
printfn "%A" one
printfn "%A" two
printfn "%A" three
printfn "%A" rightWayRound
#1 تعریف لیستی که دارای یک آیتم است.
#2 تعریف لیستی که دارای دو آیتم است(آیتم دوم لیست خود از نوع لیست است)
#3 تعریف لیستی که دارای سه آیتم است(ایتم دوم لیست خود از نوع لیستی است که دارای دو آیتم است)
# از تابع List.rev برای معکوس کردن آیتم‌های لیست three استفاده کردیم و مقادیر در لیستی به نام  rightWayRound قرار گرفت.
#5 تابع main برای چاپ اطلاعات لیست ها
بعد از اجرا خروجی زیر مشاهده می‌شود.
["one "]
["two "; "one "]
["three "; "two "; "one "]
["one "; "two "; "three "]
تفاوت بین لیست‌ها در #F و لیست و آرایه در دات نت(System.Collection.Generic)

 F#List
Net Array
 Net List
 #1 امکان تغییر در عناصر لیست
 NoYes
 Yes
 #2 امکان اضافه کردن عنصر جدید
 NoNo
 Yes
#3 جستجو
On
O1
O1
#1 در #F بعد از ساختن یک لیست امکان تغییر در مقادیر عناصر آن وجود ندارد.
#2 در #F بعد از ساختن یک لیست دیگه نمی‌تونید یک عنصر جدید به لیست اضافه کنید.
#3 جستجوی در لیست‌های #F به نسبت لیست‌ها و آرایه‌های در دات نت کند‌تر عمل می‌کند.

استفاده از عبارات در لیست ها
برای تعریف محدوده در لیست می‌تونیم به راحتی از روش زیر استفاده کنیم
let rangeList = [1..99]
برای ساخت لیست‌ها به صورت داینامیک استفاده از حلقه‌های تکرار در لیست مجاز است.
let dynamicList = [for x in 1..99 -> x*x]
کد بالا معادل کد زیر در #C  است.
for(int x=0;x<99 ; x++)
{
   myList.Add(x*x);
}
لیست‌ها و الگوی Matching
روش عادی برای کار با لیست‌ها در #F استفاده از الگوی Matching و توابع بازگشتی است.
let listOfList = [[2; 3; 5]; [7; 11; 13]; [17; 19; 23; 29]]

let rec concatList l =
match l with
| head :: tail -> head @ (concatList tail)
| [] -> []

let primes = concatList listOfList

printfn "%A" primes
در مثال بالا ابتدا یک لیست تعریف کردیم که دارای 3 آیتم است و هر آیتم آن خود یک لیست با سه آیتم است.(تمام آیتم‌ها از نوع داده عددی هستند). یک تابع بازگشتی برای پیمایش تمام آیتم‌های لیست نوشتم که در اون از الگوی Matching استفاده کردیم.
خروجی :
[2; 3; 5; 7; 11; 13; 17; 19; 23; 29]
ماژول لیست
در جدول زیر تعدادی از توابع ماژول لیست رو مشاهده می‌کنید.

 نام تابع
 توضیحات
 List.length  تابعی که طول لیست را برمی گرداند
 List.head  تابعی برای برگشت عنصر اول لیست
 List.tail  تمام عناصر لیست را بر میگرداند به جز عنصر اول
 List.init  یک لیست با توجه به تعداد آیتم ایجاد می‌کند و یم تابع را بر روی تک تک عناصر لیست ایجاد می‌کند.
 List.append  یک لیست را به عنوان ورودی دریافت می‌کند و به لیست مورد نظر اضافه می‌کند و مجموع دو لیست را برگشت می‌دهد
 List.filter  فقط عناصری را برگشت می‌دهد که شرط  مورد نظر بر روی آن‌ها مقدار true را برگشت دهد
 List.map  یک تابع مورد نظر را بر روی تک تک عناصر لیست اجرا می‌کند و لیست جدید را برگشت می‌دهد
 List.iter  یک تابع مورد نظر را بر روی تک تک عناصر لیست اجرا می‌کند  
 List.zip 
 مقادیر دو لیست را با هم تجمیع می‌کند و لیست جدید را برگشت می‌دهد. اگر طول 2 لیست ورودی یکی نباشد خطا رخ خواهدداد 
 List.unzip درست برعکس تابع بالا عمل می‌کند
 List.toArray  لیست را تبدیل به آرایه می‌کند
 List.ofArray آرایه را تبدیل به لیست می‌کند
مثال هایی از توابع بالا
 List.head [5; 4; 3]

List.tail [5; 4; 3]

List.map (fun x -> x*x) [1; 2; 3]

List.filter (fun x -> x % 3 = 0) [2; 3; 5; 7; 9]

Sequence Collection

seq در #F یک توالی از عناصری است که هم نوع باشند. عموما از sequence‌ها زمانی استفاده میکنیم که یک مجموعه از داده‌ها با تعداد زیاد و مرتب شده داشته باشیم ولی نیاز به استفاده از تمام عناصر آن نیست. کارایی sequence  در مجموعه‌های با تعداد زیاد از list‌ها به مراتب بهتر است. sequence‌‌ها را با تابع  seq می‌شناسند که معادل IEnumerable در دات نت است. بنابر این هر مجمو عه ای که IEnumerable رو در دات نت پیاده سازی کرده باشد در #F با seq قابل استفاده است.

مثال هایی از نحوه استفاده seq

#1 seq بامحدوده 1 تا 100 و توالی 10 
seq { 0 .. 10 .. 100 }
#2 استفاده از حلقه‌های تکرار برای تعریف محدوده و توالی در seq
seq { for i in 1 .. 10 do yield i * i }
#3 استفاده از <- به جای yield
seq { for i in 1 .. 10 -> i * i }
#4 استفاده از حلقه for به همراه شرط برای فیلتر کردن
let isprime n =
    let rec check i =
        i > n/2 || (n % i <> 0 && check (i + 1))
    check 2

let aSequence = seq { for n in 1..100 do if isprime n then yield n }
چگونگی استفاده از توابع seq
در این بخش به ارائه مثال هایی کاربردی‌تر از چگونگی استفاده از seq در #F می‌پردازیم. برای شروع نحوه ساخت یک seq خالی یا empty رو خواهم گفت.
let seqEmpty = Seq.empty
روش ساخت یک seq که فقط یک عنصر را برگشت می‌دهد.
let seqOne = Seq.singleton 10
برای ساختن یک seq همانند لیست‌ها می‌تونیم از seq.init استفاده کنیم. عدد 5 که بلافاصله بعد از تابع seq.init آمده است نشان دهنده تعداد آیتم‌ها موجود در seq خواهد بود. seq.iter هم یک تابع مورد نظر رو بر روی تک تک عناصر seq اجرا خواهد کرد.(همانند list.iter)
let seqFirst5MultiplesOf10 = Seq.init 5 (fun n -> n * 10)
Seq.iter (fun elem -> printf "%d " elem) seqFirst5MultiplesOf10
خروجی مثال بالا
0 10 20 30 40
با استفاده از توابع seq.ofArray , seq.ofList می‌تونیم seq مورد نظر خود را از لیست یا آرایه مورد نظر بسازیم.
let seqFromArray2 = [| 1 .. 10 |] |> Seq.ofArray 
البته این نکته رو هم یادآور بشم که به کمک عملیات تبدیل نوع(type casting) هم می‌تونیم آرایه رو به seq تبدیل کنیم. به صورت زیر
let seqFromArray1 = [| 1 .. 10 |] :> seq<int>
برای مشخص کردن اینکه آیا یک آیتم در seq موجود است یا نه می‌تونیم از seq.exists به صورت زیر استفاده کنیم.
let containsNumber number seq1 = Seq.exists (fun elem -> elem = number) seq1
let seq0to3 = seq {0 .. 3}
printfn "For sequence %A, contains zero is %b" seq0to3 (containsNumber 0 seq0to3)
اگر seq پاس داده شده به تابع exists خالی باشد یا یک ArgumentNullException متوقف خواهید شد.

برای جستجو و پیدا کردن یک آیتم در seq می‌تونیم از seq.find استفاده کنیم.
let isDivisibleBy number elem = elem % number = 0
let result = Seq.find (isDivisibleBy 5) [ 1 .. 100 ]
printfn "%d " result
دقت کنید که اگر هیچ آیتمی در sequence با  predicate مورد نظر پیدا نشود یک KeyNotFoundException رخ خواهد داد. در صورتی که مایل نباشید که استثنا رخ دهد می‌توانید از تابع seq.tryFind استفاده کنید. هم چنین خالی بودن sequence ورودی باعث ArgumentNullExceptionخواهد شد.

استفاده از lambda expression در توابع
lamdaExpressoion از توانایی‌ها مورد علاقه برنامه نویسان دات نت است و کمتر کسی است حاضر به استفاده از آن در کوئری‌های linq نباشد. در #F نیز می‌توانید از lambda Expression استفاده کنید. در ادامه به بررسی مثال هایی از این دست خواهیم پرداخت.

تابع skipWhile
همانند skipWhile در linq عمل می‌کند. یعنی یک predicate مورد نظر را بر روی تک تک عناصر یک لیست اجرا می‌کند و آیتم هایی که شرط برای آن‌ها true باشد نادیده گرفته میشوند و مابقی آیتم‌ها برگشت داده می‌شوند.
let mySeq = seq { for i in 1 .. 10 -> i*i }
let printSeq seq1 = Seq.iter (printf "%A ") seq1; printfn "" 
let mySeqSkipWhileLessThan10 = Seq.skipWhile (fun elem -> elem < 10) mySeq
mySeqSkipWhileLessThan10 |> printSeq
می‌بینید که predicate مورد نظر برای تابع skipWhile به صورت lambda expression است که با رنگ متفاوت نمایش داده شده است.(استفاده از کلمه fun).
 خروجی به صورت زیر است:
16 25 36 49 64 81 100
 برای بازگرداندن یک تعداد مشخص از آیتم‌های seq می‌تونید از توابع seq.take یا seq.truncate استفاده کنید. ابتدا باید تعداد مورد نظر و بعد لیست مورد نظر را به عنوان پارامتر مقدار دهی کنید.
مثال:
let mySeq = seq { for i in 1 .. 10 -> i*i }
let truncatedSeq = Seq.truncate 5 mySeq
let takenSeq = Seq.take 5 mySeq

let printSeq seq1 = Seq.iter (printf "%A ") seq1; printfn "" 
#1 truncatedSeq |> printSeq #3 takenSeq |> printSeq
خروجی
1 4 9 16 25 //truncate
1 4 9 16 25 //take

Tuples
tuples در #F به گروهی از مقادیر بی نام ولی مرتب شده که می‌توانند انواع متفاوت هم داشته باشند گفته می‌شود. ساختار کلی آن به صورت ( element , ... , element )  است که هر element خود می‌تواند یک عبارت نیز باشد.(مشابه کلاس Tuple در #C که به صورت generic استفاده می‌کنیم)
// Tuple of two integers.
( 1, 2 ) 

// Triple of strings.
( "one", "two", "three" ) 

// Tuple of unknown types.
( a, b ) 

// Tuple that has mixed types.
( "one", 1, 2.0 ) 

// Tuple of integer expressions.
( a + 1, b + 1)
نکات استفاده از tuple
#1 می‌تونیم از الگوی Matching برای دسترسی به عناصر tuple استفاده کنیم.
let print tuple1 =
   match tuple1 with
    | (a, b) -> printfn "Pair %A %A" a b
#2 میتونیم از let  برای تعربف الگوی tuple استفاده کنیم.
let (a, b) = (1, 2)
#3 توابع fst و snd مقادیر اول و دوم هر tuple رو بازگشت می‌دهند
let c = fst (1, 2) // return 1
let d = snd (1, 2)// return 2
#4 تابعی برای بازگشت عنصر سوم یک tuple وجود ندارد ولی این تابع رو با هم می‌نویسیم:
let third (_, _, c) = c
کاربرد tuple در کجاست
زمانی که یک تابع باید بیش از یک مقدار را بازگشت دهد از tuple‌ها استفاده می‌کنیم. برای مثال
let divRem a b = 
   let x = a / b
   let y = a % b
   (x, y)
خروجی تابع divRem از نوع tuple که دارای 2 مقدار است می‌باشد.
نظرات مطالب
کاربرد Mixins در Vue.js
یک نکته‌ی تکمیلی: آشنایی با vue-property-decorator در vuejs

اگر با Angular آشنایی داشته باشید، میدانید که برای نوشتن کامپوننت از @Component استفاده می‌کنیم. یعنی با استفاده از decoratorها می‌توانیم کامپوننتهای پیچیده‌ای را بنویسیم.  در پروژه‌های vue.js نیز کتابخانه مشابهی وجود دارد که کار نوشتن کامپوننت‌ها را ساده میکند؛ مانند کتابخانه vue-property-decorator که سورس گیت هاب آن در اینجا  قرار دارد. برای کار با آن ابتدا کتابخانه‌های vue-class-component و vue-property-decorator را به پروژه‌ی خود از طریق دستور زیر اضافه می‌کنیم:
npm install vue-class-component vue-property-decorator --save-dev
برای نوشتن کامپوننت با استفاده از  type-script ابتدا باید کلاسهای مورد نظر را import کنید و کامپوننت را از Vue مشتق کنید:
<template>
  <div>
    <p>Long-form v-model example</p>
    <input :value="myDataProperty" @input="updateMyProperty($event)"/>
  </div>
</template>

<script>
import Vue from 'vue'
import { Component } from 'vue-property-decorator'

@Component
export default class App extends Vue {
  // Data property
  myDataProperty: string;

  // Lifecycle hook
  mounted () {
    this.myDataProperty = 'Boop'
  }

  // Component method
  updateMyProperty ($event) {
    this.myDataProperty = $event.target.value
  }
}
</script>
همانطورکه مشاهده می‌کنید، مانند Angular برای تعریف کامپوننت از @Component استفاده می‌کنیم. @Component(componentConfig) شامل تنظیماتی هست که می‌توانید آن را نیز به کامپوننت مورد نظر اعمال کنید :
@Component({ name: 'App', components: { AppModal } })
که در اینجا نام کامپوننت و کامپوننت‌های استفاده شده در آن را تعریف کردیم.
در این کتابخانه، decoratorهای دیگری نیز برای استفاده وجود دارند؛ شامل:
@Prop
@PropSync
@Provide
@Model
@Watch
@Inject
@Provide
@Emit
به عنوان مثال در صورتیکه بخواهیم در کامپوننت فوق از prop استفاده کنیم، به صورت زیر می‌باشد:
import { Vue, Component, Prop } from 'vue-property-decorator'

@Component
export default class YourComponent extends Vue {
  @Prop(Number) readonly propA: number | undefined
  @Prop({ default: 'default value' }) readonly propB!: string
  @Prop([String, Boolean]) readonly propC: string | boolean | undefined
}
که در واقع این کد، معادل کد جاواسکریپتی هست که بدون استفاده از این کتابخانه می‌نویسیم:
export default {
  props: {
    propA: {
      type: Number
    },
    propB: {
      default: 'default value'
    },
    propC: {
      type: [String, Boolean]
    }
  }
}
اشتراک‌ها
معرفی TypeScript 2 توسط Anders Hejlsberg

In this video Anders Hejlsberg spends some time discussing TypeScript. He starts with the reasons behind creating TypeScript (the so called elevator speech) and then moves on to some of the features coming in the next release. He mentions a number of features but spends the time discussing the null (and corresponding undefined) types and how TypeScript 2 makes handling them much easier. 

معرفی TypeScript 2 توسط Anders Hejlsberg