هنگام ایجاد یک Type جدید باید سعی کنیم دیتای داخلی Type را تا حد ممکن Immutable کنیم. حتی اگر نیاز داریم یک شیء را برگردانیم، بهتر است که یک instance جدید را برگردانیم، نه اینکه همان شیء موجود را تغییر دهیم. نتیحه این کار نهایتا به شفافیت بیشتر و Thread-Safe بودن منجر خواهد شد.
مثال:
public class Rectangle { public int Length { get; set; } public int Height { get; set; } public void Grow(int length, int height) { Length += length; Height += height; } } Rectangle r = new Rectangle(); r.Length = 5; r.Height = 10; r.Grow(10, 10);// r.Length is 15, r.Height is 20, same instance of r
// After public class ImmutableRectangle { int Length { get; } int Height { get; } public ImmutableRectangle(int length, int height) { Length = length; Height = height; } public ImmutableRectangle Grow(int length, int height) => new ImmutableRectangle(Length + length, Height + height); } ImmutableRectangle r = new ImmutableRectangle(5, 10); r = r.Grow(10, 10);// r.Length is 15, r.Height is 20, is a new instance of r
یکی از موارد با اهمیت در سبک کد نویسی تابعی را در مثال زیر ببینید:
public static void Main() { Console.WriteLine(GetSalutation(DateTime.Now.Hour)); } // imparitive, mutates state to produce a result /*public static string GetSalutation(int hour) { string salutation; // placeholder value if (hour < 12) salutation = "Good Morning"; else salutation = "Good Afternoon"; return salutation; // return mutated variable }*/ public static string GetSalutation(int hour) => hour < 12 ? "Good Morning" : "Good Afternoon";
در قسمت قبلی درباره توابع HOF صحبت کردیم. به طور خلاصه توابعی که یک تابع را به عنوان ورودی میگیرند و یک تابع را به عنوان خروجی برمیگردانند. به مثال زیر توجه کنید:
public static int Count<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) { int count = 0; foreach (TSource element in source) { checked { if (predicate(element)) { count++; } } } return count; }
ترکیب توابع به عمل پیوند دادن چند تابع ساده، برای ایجاد توابعی پیچیده گفته میشود. دقیقا مانند عملی که در ریاضیات انجام میشود. خروجی هر تابع به عنوان ورودی تابع بعدی مورد استفاده قرار میگیرد و در آخر ما خروجی آخرین فراخوانی را به عنوان نتیجه دریافت میکنیم. ما میتوانیم در #C به روش برنامه نویسی تابعی، توابع را با یکدیگر ترکیب کنیم. به مثال زیر توجه کنید:
public static class Extensions { public static Func<T, TReturn2> Compose<T, TReturn1, TReturn2>(this Func<TReturn1, TReturn2> func1, Func<T, TReturn1> func2) { return x => func1(func2(x)); } } public class Program { public static void Main(string[] args) { Func<int, int> square = (x) => x * x; Func<int, int> negate = x => x * -1; Func<int, string> toString = s => s.ToString(); Func<int, string> squareNegateThenToString = toString.Compose(negate).Compose(square); Console.WriteLine(squareNegateThenToString(2)); } }
یکی از روشهای مهم در سبک برنامه نویسی تابعی، فراخوانی متدها به صورت زنجیرهای و پاس دادن خروجی یک متد به متد بعدی، به عنوان ورودی است. به عنوان مثال کلاس String Builder یک مثال خوب از این نوع پیاده سازی است. کلاس StringBuilder از پترن Fluent Builder استفاده میکند. ما میتوانیم با اکستنشن متد هم به همین نتیجه برسیم. نکته مهم در مورد کلاس StringBuilder این است که این کلاس، شیء string را mutate نمیکند؛ به این معنا که هر متد، تغییری در object ورودی نمیدهد و یک خروجی جدید را بر میگرداند.
string str = new StringBuilder() .Append("Hello ") .Append("World ") .ToString() .TrimEnd() .ToUpper();
public static class Extensions { public static StringBuilder AppendWhen(this StringBuilder sb, string value, bool predicate) => predicate ? sb.Append(value) : sb; } public class Program { public static void Main(string[] args) { // Extends the StringBuilder class to accept a predicate string htmlButton = new StringBuilder().Append("<button").AppendWhen(" disabled", false).Append(">Click me</button>").ToString(); } }
نوعهای اضافی درست نکنید ، به جای آن از کلمهی کلیدی yield استفاده کنید!
گاهی ما نیاز داریم لیستی از آیتمها را به عنوان خروجی یک متد برگردانیم. اولین انتخاب معمولا ایجاد یک شیء از جنس List یا به طور کلیتر Collection و سپس استفاده از آن به عنوان نوع خروجی است:
public static void Main() { int[] a = { 1, 2, 3, 4, 5 }; foreach (int n in GreaterThan(a, 3)) { Console.WriteLine(n); } } /*public static IEnumerable<int> GreaterThan(int[] arr, int gt) { List<int> temp = new List<int>(); foreach (int n in arr) { if (n > gt) temp.Add(n); } return temp; }*/ public static IEnumerable<int> GreaterThan(int[] arr, int gt) { foreach (int n in arr) { if (n > gt) yield return n; } }
در قسمت قبلی به طور کلی درباره برنامه نویسی Imperative صحبت کردیم. در مثال زیر یک نمونه از تبدیل یک متد که با استایل Imperative نوشته شده به declarative را میبینید. شما میتوانید ببینید که چقدر کوتاهتر و خواناتر شده:
List<int> collection = new List<int> { 1, 2, 3, 4, 5 }; // Imparative style of programming is verbose List<int> results = new List<int>(); foreach(var num in collection) { if (num % 2 != 0) results.Add(num); } // Declarative is terse and beautiful var results = collection.Where(num => num % 2 != 0);
Immutable Collection
در مورد اهمیت immutable قبلا صحبت کردیم؛ Immutable Collection ها، کالکشنهایی هستند که به جز زمانیکه ایجاد میشنود، اعضای آنها نمیتوانند تغییر کنند. زمانیکه یک آیتم به آن اضافه یا کم شود، یک لیست جدید، برگردانده خواهد شد. شما میتوانید انواع این کالکشنها را در این لینک ببینید.
به نظر میرسد که ایجاد یک کالکشن جدید میتواند سربار اضافی بر روی استفاده از حافظه داشته باشد، اما همیشه الزاما به این صورت نیست. به طور مثال اگر شما f(x)=y را داشته باشید، مقادیر x و y به احتمال زیاد یکسان هستند. در این صورت متغیر x و y، حافظه را به صورت مشترک استفاده میکنند. به این دلیل که هیچ کدام از آنها Mutable نیستند. اگر به دنبال جزییات بیشتری هستید این مقاله به صورت خیلی جزییتر در مورد نحوه پیاده سازی این نوع کالکشنها صحبت میکند. اریک لپرت یک سری مقاله در مورد Immutable ها در #C دارد که میتوانید آن هار در اینجا پیدا کنید.
Thread-Safe Collections
Collection | توضیحات |
ConcurrentDictionary | پیاده سازی thread safe از دیکشنری key-value |
ConcurrentQueue | پیاده سازی thread safe از صف (اولین ورودی ، اولین خروجی) |
ConcurrentStack | پیاده سازی thread safe از پشته (آخرین ورودی ، اولین خروجی) |
ConcurrentBag | پیاده سازی thread safe از لیست نامرتب |
این کلاسها در واقع همه مشکلات ما را حل نخواهند کرد؛ اما بهتر است که در ذهن خود داشته باشیم که بتوانیم به موقع و در جای درست از آنها استفاده کنیم.
در این قسمت از مقاله سعی شد با روشهای خیلی ساده، با مفاهیم اولیه برنامه نویسی تابعی درگیر شویم. در ادامه مثالهای بیشتری از الگوهایی که میتوانند به ما کمک کنند، خواهیم داشت.
وبلاگها و سایتهای ایرانی
Visual Studio
امنیت
- رمزنگاری کوانتمی و شبکهای رمزنگاری شده با این روش
ASP. Net
طراحی وب
اسکیوال سرور
به روز رسانیها
ابزارها
- نگارش جدید برنامه RSS Bandit . (برنامهای سورس باز نوشته شده با سی شارپ)
- Visual Round Trip Analyzer (استفاده از NetMon API)
سیشارپ
- Interactive GUI Shell از توسعه دهندگان تیم Mono
عمومی دات نت
- آشنایی با کلاس CommaDelimitedStringCollection در دات نت فریم ورک
- مونو و دات نت گزارشی از PDC2008
CPP
دلفی
- CompilerPlugin برای دلفی 2009. (توسط آن میتوان پروژههای دلفی 2007 را با دلفی 2009 نیز کامپایل کرد)
- نسخه جدید CnPack منتشر شد. (با پشتیبانی دلفی 5 تا 2009)
ویندوز
- آنالیز crash dumps ویندوز . (آیا میدانید صفحات آبی ویندوز را چگونه باید تفسیر کرد؟)
Office
- آشنایی با یک سری از اصطلاحات outlook 2007 برای برنامه نویسها. (اگر قصد داشته باشید یک add-in را برای outlook 2007 با استفاده از امکانات VSTO توسعه دهید، آشنایی با این اصطلاحات بسیار ضروری خواهد بود)
متفرقه
شروع کار با webpack - قسمت دوم
//package.json file { "name": "dntwebpack", "version": "1.0.0", "description": "", "main": "main.js", "scripts": { "webpack": "webpack", "webpackserver": "webpack-dev-server" ,"start": "npm run webpackserver" // یا فراخوانی مستقیم وبپک به این صورت ، دقت کنید که یکی از این دو باید حضور داشته باشد , "start":"webpack-dev-server" } }
Service Layer
نقش لایهی سرویس این است که به عنوان یک مدخل ورودی به برنامه کاربردی عمل کند. در برخی مواقع این لایه را به عنوان لایهی Facade نیز میشناسند. این لایه، دادهها را در قالب یک نوع داده ای قوی (Strongly Typed) به نام View Model، برای لایهی Presentation فراهم میکند. کلاس View Model یک Strongly Typed محسوب میشود که نماهای خاصی از دادهها را که متفاوت از دید یا نمای تجاری آن است، بصورت بهینه ارائه مینماید. در مورد الگوی View Model در مباحث بعدی بیشتر صحبت خواهم کرد.
الگوی Facade یک Interface ساده را به منظور کنترل دسترسی به مجموعه ای از Interfaceها و زیر سیستمهای پیچیده ارائه میکند. در مباحث بعدی در مورد آن بیشتر صحبت خواهم کرد.
کلاسی با نام ProductViewModel را با کد زیر به پروژه SoCPatterns.Layered.Service اضافه کنید:
public class ProductViewModel { Public int ProductId {get; set;} public string Name { get; set; } public string Rrp { get; set; } public string SellingPrice { get; set; } public string Discount { get; set; } public string Savings { get; set; } }
برای اینکه کلاینت با لایهی سرویس در تعامل باشد باید از الگوی Request/Response Message استفاده کنیم. بخش Request توسط کلاینت تغذیه میشود و پارامترهای مورد نیاز را فراهم میکند. کلاسی با نام ProductListRequest را با کد زیر به پروژه SoCPatterns.Layered.Service اضافه کنید:
using SoCPatterns.Layered.Model; namespace SoCPatterns.Layered.Service { public class ProductListRequest { public CustomerType CustomerType { get; set; } } }
در شی Response نیز بررسی میکنیم که درخواست به درستی انجام شده باشد، دادههای مورد نیاز را برای کلاینت فراهم میکنیم و همچنین در صورت عدم اجرای صحیح درخواست، پیام مناسب را به کلاینت ارسال مینماییم. کلاسی با نام ProductListResponse را با کد زیر به پروژه SoCPatterns.Layered.Service اضافه کنید:
public class ProductListResponse { public bool Success { get; set; } public string Message { get; set; } public IList<ProductViewModel> Products { get; set; } }
به منظور تبدیل موجودیت Product به ProductViewModel، به دو متد نیاز داریم، یکی برای تبدیل یک Product و دیگری برای تبدیل لیستی از Product. شما میتوانید این دو متد را به کلاس Product موجود در Domain Model اضافه نمایید، اما این متدها نیاز واقعی منطق تجاری نمیباشند. بنابراین بهترین انتخاب، استفاده از Extension Methodها میباشد که باید برای کلاس Product و در لایهی سرویس ایجاد نمایید. کلاسی با نام ProductMapperExtensionMethods را با کد زیر به پروژه SoCPatterns.Layered.Service اضافه کنید:
public static class ProductMapperExtensionMethods { public static ProductViewModel ConvertToProductViewModel(this Model.Product product) { ProductViewModel productViewModel = new ProductViewModel(); productViewModel.ProductId = product.Id; productViewModel.Name = product.Name; productViewModel.RRP = String.Format(“{0:C}”, product.Price.RRP); productViewModel.SellingPrice = String.Format(“{0:C}”, product.Price.SellingPrice); if (product.Price.Discount > 0) productViewModel.Discount = String.Format(“{0:C}”, product.Price.Discount); if (product.Price.Savings < 1 && product.Price.Savings > 0) productViewModel.Savings = product.Price.Savings.ToString(“#%”); return productViewModel; } public static IList<ProductViewModel> ConvertToProductListViewModel( this IList<Model.Product> products) { IList<ProductViewModel> productViewModels = new List<ProductViewModel>(); foreach(Model.Product p in products) { productViewModels.Add(p.ConvertToProductViewModel()); } return productViewModels; } }
حال کلاس ProductService را جهت تعامل با کلاس سرویس موجود در Domain Model و به منظور برگرداندن لیستی از محصولات و تبدیل آن به لیستی از ProductViewModel، ایجاد مینماییم. کلاسی با نام ProductService را با کد زیر به پروژه SoCPatterns.Layered.Service اضافه کنید:
public class ProductService { private Model.ProductService _productService; public ProductService(Model.ProductService ProductService) { _productService = ProductService; } public ProductListResponse GetAllProductsFor( ProductListRequest productListRequest) { ProductListResponse productListResponse = new ProductListResponse(); try { IList<Model.Product> productEntities = _productService.GetAllProductsFor(productListRequest.CustomerType); productListResponse.Products = productEntities.ConvertToProductListViewModel(); productListResponse.Success = true; } catch (Exception ex) { // Log the exception… productListResponse.Success = false; // Return a friendly error message productListResponse.Message = ex.Message; } return productListResponse; } }
کلاس Service تمامی خطاها را دریافت نموده و پس از مدیریت خطا، پیغامی مناسب را به کلاینت ارسال میکند. همچنین این لایه محل مناسبی برای Log کردن خطاها میباشد. در اینجا کد نویسی لایه سرویس به پایان رسید و در ادامه به کدنویسی Data Layer میپردازیم.
Data Layer
برای ذخیره سازی محصولات، یک بانک اطلاعاتی با نام Shop01 ایجاد کنید که شامل جدولی به نام Product با ساختار زیر باشد:
برای اینکه کدهای بانک اطلاعاتی را سریعتر تولید کنیم از روش Linq to SQL در Data Layer استفاده میکنم. برای این منظور یک Data Context برای Linq to SQL به این لایه اضافه میکنیم. بر روی پروژه SoCPatterns.Layered.Repository کلیک راست نمایید و گزینه Add > New Item را انتخاب کنید. در پنجره ظاهر شده و از سمت چپ گزینه Data و سپس از سمت راست گزینه Linq to SQL Classes را انتخاب نموده و نام آن را Shop.dbml تعیین نمایید.
از طریق پنجره Server Explorer به پایگاه داده مورد نظر متصل شوید و با عمل Drag & Drop جدول Product را به بخش Design کشیده و رها نمایید.
اگر به یاد داشته باشید، در لایه Model برای برقراری ارتباط با پایگاه داده از یک Interface به نام IProductRepository استفاده نمودیم. حال باید این Interface را پیاده سازی نماییم. کلاسی با نام ProductRepository را با کد زیر به پروژه SoCPatterns.Layered.Repository اضافه کنید:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using SoCPatterns.Layered.Model; namespace SoCPatterns.Layered.Repository { public class ProductRepository : IProductRepository { public IList<Model.Product> FindAll() { var products = from p in new ShopDataContext().Products select new Model.Product { Id = p.ProductId, Name = p.ProductName, Price = new Model.Price(p.Rrp, p.SellingPrice) }; return products.ToList(); } } }
در متد FindAll، با استفاده از دستورات Linq to SQL، لیست تمامی محصولات را برگرداندیم. کدنویسی لایهی Data هم به پایان رسید و در ادامه به کدنویسی لایهی Presentation و UI میپردازیم.
Presentation Layer
به منظور جداسازی منطق نمایش (Presentation) از رابط کاربری (User Interface)، از الگوی Model View Presenter یا همان MVP استفاده میکنیم که در مباحث بعدی با جزئیات بیشتری در مورد آن صحبت خواهم کرد. یک Interface با نام IProductListView را با کد زیر به پروژه SoCPatterns.Layered.Presentation اضافه کنید:
using SoCPatterns.Layered.Service; public interface IProductListView { void Display(IList<ProductViewModel> Products); Model.CustomerType CustomerType { get; } string ErrorMessage { set; } }
این Interface توسط Web Formهای ASP.NET و یا Win Formها باید پیاده سازی شوند. کار با Interfaceها موجب میشود تا تست Viewها به راحتی انجام شوند. کلاسی با نام ProductListPresenter را با کد زیر به پروژه SoCPatterns.Layered.Presentation اضافه کنید:
using SoCPatterns.Layered.Service; namespace SoCPatterns.Layered.Presentation { public class ProductListPresenter { private IProductListView _productListView; private Service.ProductService _productService; public ProductListPresenter(IProductListView ProductListView, Service.ProductService ProductService) { _productService = ProductService; _productListView = ProductListView; } public void Display() { ProductListRequest productListRequest = new ProductListRequest(); productListRequest.CustomerType = _productListView.CustomerType; ProductListResponse productResponse = _productService.GetAllProductsFor(productListRequest); if (productResponse.Success) { _productListView.Display(productResponse.Products); } else { _productListView.ErrorMessage = productResponse.Message; } } } }
کلاس Presenter وظیفهی واکشی داده ها، مدیریت رویدادها و بروزرسانی UI را دارد. در اینجا کدنویسی لایهی Presentation به پایان رسیده است. از مزایای وجود لایهی Presentation این است که تست نویسی مربوط به نمایش دادهها و تعامل بین کاربر و سیستم به سهولت انجام میشود بدون آنکه نگران دشواری Unit Test نویسی Web Formها باشید. حال میتوانید کد نویسی مربوط به UI را انجام دهید که در ادامه به کد نویسی در Win Forms و Web Forms خواهیم پرداخت.
پشتیبانی از XML Schema در SQL Server
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
اگر علاقمند باشید تا این تعاریف را مشاهده کنید به مسیر 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>
<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>
تعریف 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) )
در ادامه نحوهی تعریف یک اسکیمای نمونه قابل مشاهده است:
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>'
اکنون برای آزمایش اسکیمای تعریف شده، جدول 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>')
در این مثال، insert اول با موفقیت انجام خواهد شد؛ اما insert دوم با خطای ذیل متوقف میشود:
XML Validation: Invalid simple type value: 'test'. Location: /*:Point[1]/*:Y[1]
یافتن محل ذخیره سازی اطلاعات اسکیما در 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
محتوای اسکیمای ذخیره شده به شکل 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)
نحوهی ویرایش یک 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
نحوهی 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 برای خواندن یک فایل 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 تولید کند. اطلاعات بیشتر
از ویندوز ویستا به بعد، ویندوز به صورت توکار دارای یک موتور تشخیص صدا شده است که در این مسیر قابل مشاهده میباشد:
این سرویس از طریق اسمبلی استاندارد System.Speech در دات نت فریم ورک قابل استفاده است که اکنون با برنامهی Subtitle tools یکپارچه شده است.
یکی از خصوصیات مفید این موتور تشخیص صدا، امکان دریافت فایلهای صوتی نیز میباشد. فایل صوتی دریافتی باید مطابق یکی از فرمتهای پشتیبانی شده توسط آن، تهیه شود؛ که این مورد را ذیل قسمت Supported audio formats شکل فوق میتوانید مشاهده کنید.
برای نمونه توسط برنامه AoA Audio Extractor Basic، میتوان این تبدیلات را انجام داد و یکی از تنظیمات قابل قبول توسط موتور Speech Recognition ویندوز 7 را در تصویر ذیل میتوانید مشاهده کنید: (و در غیراینصورت هیچ خروجی را نخواهید گرفت؛ خیلی مهم!)
پس از انتخاب و گشودن فایل صوتی در برنامه Subtitle tools (کلیک بر روی دکمه Open WAV در اینجا) و سپس کلیک بر روی دکمهی Recognize یا Start ، کار موتور Speech Recognition ویندوز شروع شده و برنامه هم در اینجا از فرصت استفاده کرده و دریافتی نهایی را تبدیل به رکوردهای فایل زیرنویس میکند که نمونهای از آنرا در شکل فوق میتوانید ملاحظه کنید.
نکاتی در مورد استفاده بهینه از موتور تشخیص صدای ویندوز:
الف) برای آزمایش برنامه، یک فایل voice را از اینجا دریافت کنید. این فایل voice از همان سری مترو PluralSight تهیه شده است.
ابتدا موتور تشخیص صدای انتخابی را بر روی حالت US قرار داده و تست کنید. در ادامه یکبار هم برروی حالت UK قرار دهید و کار تشخیص صدا را آغاز نمائید.
نتایج کاملا متفاوت خواهند بود و با توجه به لهجه انگلیسی گوینده، تشخیصهای حالت UK، به واقعیت نزدیکتر هستند. این مورد را در گزینهی Average confidence هم میتوانید مشاهده نمائید. مثلا در اینجا موتور تشخیص صدا در کل به 60 درصد خروجی تولیدیاش اطمینان دارد و مابقی ... آنچنان اعتباری ندارند.
مثلا متن صحیح سطر چهارم در تصویر فوق باید «when they are not in the foreground» باشد!
ب) تنظیمات Timeouts
اگر به فایل voice فوق دقت کنید، گوینده یک نفس از ابتدا تا انتها صحبت میکند. اینجا است که به کمک مقادیر Silence timeout ، میتوان تعداد رکوردها را بر اساس فواصل تنفس کوتاهتری، بیشتر کرد. مثلا با اعداد پیش فرض سیستم، با فایل صوتی فوق به 5 خروجی خواهید رسید؛ اما با توجه به تنظیماتی که در تصویر مشاهده میکنید، به 8 خروجی متعادلتر میرسیم.
مزایا:
- کار زمانبندی زیر نویس خودکار میشود.
- تا حدود 60 درصد، خروجی متنی مطمئنی را میتوان شاهد بود.
در مورد ویندوز XP :
ویندوز XP به صورت پیش فرض دارای موتور Speech Recognition نیست. دو راه برای نصب آن در این سیستم وجود دارد:
الف) استفاده از بسته نرم افزاری آفیس XP
به کنترل پنل مراجعه کرده، گزینهی Add/remove programs را انتخاب نمائید. در اینجا Microsoft Office XP را انتخاب و بر روی دکمه Change کلیک کنید. نیاز است تا یکی از ویژگیهای نصب نشده آنرا نصب کنیم. به همین جهت در صفحه ظاهر شده، Add or Remove Features را انتخاب و در ادامه در قسمت Features to install ، گزینهی Office Shared Features را انتخاب کنید. ذیل مدخل Alternative User Input، امکان انتخاب و نصب Speech مهیا است.
ب) استفاده از Microsoft Speech SDK Setup 5.1
بر روی ویندوز 7، نگارش 8 این برنامه نصب است؛ اما برای ویندوز XP تا نگارش 5.1 بیشتر ارائه نشده است. فایلهای آنرا از اینجا میتوانید دریافت کنید. نصب آن هم در اینجا توضیح داده شده.
من در کل ویندوز XP را برای اینکار توصیه نمیکنم چون هم موتور تشخیص صدای آن قدیمی است و هم حالت Asynchronous آن درست کار نمیکند. برای مثال این یک خروجی تهیه شده از همان فایل voice فوق، توسط موتور تشخیص صدای مخصوص ویندوز XP است که بیشباهت به طنز نیست!
- Updated Roslyn to
3.8.0
, MSBuild to16.8.0
, DotNetHostResolver to5.0.0
, Nuget packages to5.8.0-rc.6930
and MSBuildSDKResolver to5.0.101-servicing.20564.2
to match .NET 5.0.100 SDK (PR: omnisharp-vscode#2015, omnisharp-vscode#2016)
- Updated to NET 5.0 preview8 (PR: omnisharp-roslyn#1916)
- Update build tool versions for NET 5 RC1 (PR: omnisharp-roslyn#1926)
- Update Roslyn to 3.8.0-3.20451.2 (PR: omnisharp-roslyn#1927)