کتابخانه Responsive Tabs
آشنایی با قابلیت های SQL Server 2016
همانطور که اطلاع دارید نسخه آزمایشی SQL Server 2016 قرار از تابستان امسال (2015) در دسترس باشد. قابلیتهای جدیدی به این محصول اضافه شده است. تعدادی از آنها عبارتند از
1- امکان استفاده از Clustered Column Store Index در جداول Memory Optmized
2- َAlways Encrypted
3- پشتیبانی از JSON
4- پشتیبانی از زبان R در SQL Server
و ...
یک تجربهی مهم: نگارش 11 آن را با SQL Server X64 تست کردم کار نکرد. اما نگارش 9 کار میکند.
مستندات کامل
پس از نصب ابتدایی آن، مراحل ذیل را برای فعال سازی آن باید طی کرد:
1) تنظیم مسیر پوشه bin نصب فیلتر (مهم!)
Start > Control Panel > System > Advanced Environment Variables -> System Variables -> find PATH
C:\Program Files\Adobe\Adobe PDF iFilter 9 for 64-bit platforms\bin\
سپس کل سیستم را ری استارت کنید.
2) ثبت آن در وهلهی جاری SQL Server
برای این منظور ابتدا دستورات ذیل را جرا کنید:
exec sys.sp_fulltext_service 'load_os_resources', 1; EXEC sp_fulltext_service 'verify_signature', 0 EXEC sp_fulltext_service 'update_languages'; -- update language list EXEC sp_fulltext_service 'restart_all_fdhosts'; -- restart daemon reconfigure with override
سپس در management studio یکبار بر روی وهلهی جاری کلیک راست کرده و گزینهی Restart را انتخاب کنید (مهم).
3) پس از ریاستارت SQL Server، اطمینان حاصل کنید که این فیلتر جدید نصب شدهاست:
exec sys.sp_help_fulltext_system_components 'filter';
و یا کوئری ذیل نیز برای این منظور مفید است:
SELECT document_type, path from sys.fulltext_document_types where document_type = '.pdf'
4) در ادامه برای استفاده از آن آزمایش ذیل را ترتیب خواهیم داد.
ایجاد یک جدول جدید که فایلهای باینری PDF را در خود ذخیره میکند:
CREATE TABLE PdfDocuments ( id INT IDENTITY(1,1) NOT NULL, doctype NCHAR(4) NOT NULL, doccontent VARBINARY(MAX) NOT NULL, CONSTRAINT PK_PdfDocuments PRIMARY KEY CLUSTERED(id) );
سپس چند رکورد را در آن ثبت میکنیم. برای نمونه دو مقالهی خروجی PDF سایت جاری را در این جدول ثبت خواهیم کرد:
INSERT INTO PdfDocuments(doctype, doccontent) SELECT N'PDF', bulkcolumn FROM OPENROWSET (BULK 'C:\Users\Vahid\Downloads\1732-DotNetTips.pdf', SINGLE_BLOB) AS doc; INSERT INTO PdfDocuments(doctype, doccontent) SELECT N'PDF', bulkcolumn FROM OPENROWSET (BULK 'C:\Users\Vahid\Downloads\1733-DotNetTips.pdf', SINGLE_BLOB) AS doc;
http://msdn.microsoft.com/en-us/library/ms692560%28v=vs.85%29.aspx
-- Search property list CREATE SEARCH PROPERTY LIST PdfSearchPropertyList; GO ALTER SEARCH PROPERTY LIST PdfSearchPropertyList ADD 'Author' WITH (PROPERTY_SET_GUID = 'F29F85E0-4FF9-1068-AB91-08002B27B3D9', PROPERTY_INT_ID = 4, PROPERTY_DESCRIPTION = 'Author - author of a given item.'); GO
در اینجا اگر علاقمند بودید، stop list معرفی شده در قسمتهای قبل را نیز میتوان افزود.
CREATE FULLTEXT STOPLIST SQLStopList; GO -- Add a stopwords ALTER FULLTEXT STOPLIST SQLStopList ADD N'به' LANGUAGE 'English'; ALTER FULLTEXT STOPLIST SQLStopList ADD N'با' LANGUAGE 'English'; --.....
سپس یک کاتالوگ FTS و ایندکس Full-Text ایی را بر روی این جدول ایجاد میکنیم:
-- Full-text catalog CREATE FULLTEXT CATALOG PdfDocumentsFtCatalog; GO -- Full-text index CREATE FULLTEXT INDEX ON PdfDocuments ( [doccontent] TYPE COLUMN [doctype] Language 1033 STATISTICAL_SEMANTICS ) KEY INDEX PK_PdfDocuments ON PdfDocumentsFtCatalog WITH STOPLIST = SQLStopList, SEARCH PROPERTY LIST = PdfSearchPropertyList, CHANGE_TRACKING AUTO; GO
آیا کار میکند ؟ چیزی ایندکس شدهاست؟
SELECT I.document_id, I.display_term, I.occurrence_count FROM sys.dm_fts_index_keywords_by_document(DB_ID(DB_NAME()), OBJECT_ID(N'dbo.PdfDocuments')) AS I INNER JOIN dbo.PdfDocuments D ON D.id = I.document_id;
انجام دو کوئری بر روی آن. یکی برای یافتن متنی ساده و دیگری برای یافتن خواص
SELECT * FROM PdfDocuments WHERE CONTAINS(doccontent, N'است') SELECT I.document_id, I.display_term, I.property_id FROM sys.dm_fts_index_keywords_by_property(DB_ID(DB_NAME()), OBJECT_ID(N'dbo.PdfDocuments')) AS I INNER JOIN dbo.PdfDocuments D ON D.id = I.document_id;
کوئری نویسی مقدماتی در RavenDB
امکان استفاده از LINQ در RavenDB
RavenDB از LINQ جهت کوئری نویسی پشتیبانی میکند. برای استفاده از آن، در ادامه مطلب اول، ابتدا سرور RavenDB را اجرا نموده و سپس برنامه کنسول را به نحو ذیل تغییر دهید:
using System; using System.Linq; using Raven.Client.Document; using RavenDBSample01.Models; namespace RavenDBSample01 { class Program { static void Main(string[] args) { using (var store = new DocumentStore { Url = "http://localhost:8080" }.Initialize()) { using (var session = store.OpenSession()) { var questions = session.Query<Question>().Where(x => x.Title.StartsWith("Raven")); foreach (var question in questions) { Console.WriteLine(question.Title); } } } } } }
Available commands: cls, reset, gc, q Request # 1: GET - 179 ms - <system> - 404 - /docs/Raven/Replication/Destinations Request # 2: GET - 3,818 ms - <system> - 200 - /indexes/dynamic/Questions?&query=Title%3ARaven*&pageSize=128 Query: Title:Raven* Time: 3,494 ms Index: Auto/Questions/ByTitle Results: 2 returned out of 2 total.
var questions = session.Query<Question>().Where(x => x.Title.StartsWith("Raven")).Take(128);
ارتباط Lucene.NET و RavenDB
کل LINQ API تهیه شده در RavenDB یک محصور کننده امکانات Lucene.NET است. اگر پیشتر با Lucene.NET کار کرده باشید، در خروجی حالت دیباگ کنسول سرور فوق، سطر «Query: Title:Raven*» آشنا به نظر خواهد رسید. دقیقا کوئری LINQ نوشته شده به یک کوئری با Syntax مخصوص Lucene.NET ترجمه شدهاست. برای نمونه اگر علاقمند باشید که مستقیما کوئریهای خاص لوسین را در RavenDB اجرا کنید، از Syntax ذیل میتوان استفاده کرد:
var questions = session.Advanced.LuceneQuery<Question>().Where("Title:Raven*").ToList();
var questions = session.Advanced.LuceneQuery<Question>().WhereStartsWith(x => x.Title, "Raven").ToList();
استفاده مجدد از کوئریها در RavenDB
در RavenDB، متد Query به صورت immutable تعریف شده است و متد LuceneQuery حالت mutable دارد (ترکیبات آن نیز یک وهله است).
یک مثال:
var query = session.Query<User>().Where(x => x.Name.StartsWith("A")); var ageQuery = query.Where(x => x.Age > 21); var eyeQuery = query.Where(x => x.EyeColor == "blue");
query - Name:A* ageQuery - (Name:A*) AND (Age_Range:{Ix21 TO NULL}) eyeQuery - (Name:A*) AND (EyeColor:blue)
در ادامه اگر همین سه کوئری فوق را با فرمت LuceneQuery تهیه کنیم، به عبارات ذیل خواهیم رسید:
var luceneQuery = session.Advanced.LuceneQuery<User>().WhereStartsWith(x => x.Name, "A"); var ageLuceneQuery = luceneQuery.WhereGreaterThan(x => x.Age, 21); var eyeLuceneQuery = luceneQuery.WhereEquals(x => x.EyeColor, "blue");
luceneQuery - Name:A* ageLuceneQuery - Name:A* Age_Range:{Ix21 TO NULL} eyeLuceneQuery - Name:A* Age_Range:{Ix21 TO NULL} EyeColor:blue
And و Or شدن کوئریهای ترکیبی در RavenDB
در مثال استفاده مجدد از کوئریها، زمانیکه از Where استفاده شد، بین عبارات حاصل AND قرار گرفته است. این مورد را به نحو ذیل میتوان تنظیم کرد و مثلا به OR تغییر داد:
session.Advanced.LuceneQuery<User>().UsingDefaultOperator(QueryOperator.And);
صفحه بندی اطلاعات در RavenDB
در ابتدای بحث عنوان شد که کوئری LINQ اجرا شده در RavenDB، یک Take مخفی و پیش فرض تنظیم شده به 128 آیتم را دارد. اکنون سؤال این خواهد بود که چگونه میتوان اطلاعات را به صورت صفحه بندی شده، بر اساس شماره صفحه خاصی نمایش داد.
using System; using System.Linq; using Raven.Client.Document; using RavenDBSample01.Models; namespace RavenDBSample01 { class Program { static void Main(string[] args) { using (var store = new DocumentStore { Url = "http://localhost:8080" }.Initialize()) { using (var session = store.OpenSession()) { int pageNumber = 0; int resultsPerPage = 2; var questions = session.Query<Question>() .Where(x => x.Title.StartsWith("Raven")) .Skip(pageNumber * resultsPerPage) .Take(resultsPerPage); foreach (var question in questions) { Console.WriteLine(question.Title); } } } } } }
دریافت اطلاعات آماری کوئری اجرا شده
در RavenDB امکان دریافت یک سری اطلاعات آماری از کوئری اجرا شده نیز وجود دارد؛ برای مثال یک کوئری چند ثانیه طول کشیده است، چه تعدادی رکورد را بازگشت داده است و امثال آن. برای پیاده سازی آن، نیاز است از متد الحاقی Statistics به نحو ذیل استفاده کرد:
using System; using System.Linq; using Raven.Client.Document; using RavenDBSample01.Models; using Raven.Client; namespace RavenDBSample01 { class Program { static void Main(string[] args) { using (var store = new DocumentStore { Url = "http://localhost:8080" }.Initialize()) { using (var session = store.OpenSession()) { int pageNumber = 0; int resultsPerPage = 2; RavenQueryStatistics stats; var questions = session.Query<Question>() .Statistics(out stats) .Where(x => x.Title.StartsWith("Raven")) .Skip(pageNumber * resultsPerPage) .Take(resultsPerPage); foreach (var question in questions) { Console.WriteLine(question.Title); } Console.WriteLine("TotalResults: {0}", stats.TotalResults); } } } } }
امکانات ویژه فضای نام Raven.Client.Linq
یک سری متد الحاقی خاص جهت تهیه سادهتر کوئریهای LINQ در فضای نام Raven.Client.Linq قرار دارند که پس از تعریف آن قابل دسترسی خواهند بود:
var list = session.Query<Question>().Where(q => q.By.In<string>(arrayOfUsers))).ToArray()
SELECT * FROM tbl WHERE data IN (1, 2, 3)
اتصال به RavenDB با استفاده از برنامه معروف LINQPad
اگر علاقمند باشید که کوئریهای خود را در محیط برنامه معروف LINQPad نیز آزمایش کنید، درایور مخصوص RavenDB آنرا از آدرس ذیل میتوانید دریافت نمائید:
یکپارچه سازی اعتبارسنجی EF Code first با امکانات WPF و حذف کدهای تکرای INotifyPropertyChanged
بررسی سطح بالای مکانیزمهای اعتبارسنجی و AOP بکارگرفته شده
در حین کار با قالب پروژه WPF Framework، هنگام طراحی Modelهای خود (تفاوتی نمیکند که Domain model باشند یا صرفا Model متناظر با یک View)، نیاز است دو مورد را رعایت کنید:
[ImplementPropertyChanged] // AOP public class LoginPageModel : DataErrorInfoBase
ب) از کلاس پایه DataErrorInfoBase مشتق گردد
البته اگر به کلاسهای Domain model برنامه مراجعه کنید، صرفا مشتق شدن از BaseEntity را ملاحظه میکنید:
public class User : BaseEntity
[ImplementPropertyChanged] // AOP public abstract class BaseEntity : DataErrorInfoBase //پیاده سازی خودکار سیستم اعتبارسنجی یکپارچه
بررسی جزئیات مکانیزم AOP بکارگرفته شده
بسیار خوب؛ اینها چطور کار میکنند؟!
ابتدا نیاز است مطلب «معرفی پروژه NotifyPropertyWeaver» را یکبار مطالعه نمائید. خلاصهای جهت تکرار نکات مهم آن:
ویژگی ImplementPropertyChanged به ابزار Fody اعلام میکند که لطفا کدهای تکراری INotifyPropertyChanged را پس از کامپایل اسمبلی جاری، بر اساس تزریق کدهای IL متناظر، به اسمبلی اضافه کن. این روش از لحاظ کارآیی و همچنین تمیز نگه داشتن کدهای نهایی برنامه، فوق العاده است.
برای بررسی کارکرد آن نیاز است اسمبلی مثلا Models را دیکامپایل کرد:
همانطور که ملاحظه میکنید، کدهای تکراری INotifyPropertyChanged به صورت خودکار به اسمبلی نهایی اضافه شدهاند.
البته بدیهی است که استفاده از Fody الزامی نیست. اگر علاقمند هستید که این اطلاعات را دستی اضافه کنید، بهتر است از کلاس پایه BaseViewModel قرار گرفته در مسیر MVVM\BaseViewModel.cs پروژه Common استفاده نمائید.
در این کلاس، پیاده سازیهای NotifyPropertyChanged را بر اساس متدهایی که یک رشته را به عنوان نام خاصیت دریافت میکنند و یا متدی که امکان دسترسی strongly typed به نام رشته را میسر ساخته است، ملاحظه میکنید.
/// <summary> /// تغییر مقدار یک خاصیت را اطلاع رسانی خواهد کرد /// </summary> /// <param name="propertyName">نام خاصیت</param> public void NotifyPropertyChanged(string propertyName) /// <summary> /// تغییر مقدار یک خاصیت را اطلاع رسانی خواهد کرد /// </summary> /// <param name="expression">نام خاصیت مورد نظر</param> public void NotifyPropertyChanged(Expression<Func<object>> expression)
public class AlertConfirmBoxViewModel : BaseViewModel { AlertConfirmBoxModel _alertConfirmBoxModel; public AlertConfirmBoxModel AlertConfirmBoxModel { set { _alertConfirmBoxModel = value; NotifyPropertyChanged("AlertConfirmBoxModel"); // ویا .... NotifyPropertyChanged(()=>AlertConfirmBoxModel); } get { return _alertConfirmBoxModel; } }
بررسی جزئیات اعتبارسنجیهای تعریف شده
EF دارای یک سری ویژگی مانند Required و امثال آن است. WPF دارای اینترفیسی است به نام IDataErrorInfo. این دو را باید به نحوی به هم مرتبط ساخت که پیاده سازیهای مرتبط با آنها را در مسیرهای WpfValidation\DataErrorInfoBase.cs و WpfValidation\ValidationHelper.cs پروژه Common میتوانید ملاحظه نمائید.
<TextBox Text="{Binding Path=ChangeProfileData.UserName, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged, NotifyOnValidationError=true, ValidatesOnExceptions=true, ValidatesOnDataErrors=True, TargetNullValue=''}" />
همچنین حالتهای بررسی اعتبارسنجی آن نیز به PropertyChanged تنظیم گردیده است. در این حالت WPF به تعاریف شیء ChangeProfileData مراجعه کرده و برای نمونه اگر این شیء اینترفیس IDataErrorInfo را پیاده سازی کرده بود، نام خاصیت جاری را به آن ارسال و از آن خطاهای اعتبارسنجی متناظر را درخواست میکند. در اینجا وقت خواهیم داشت تا بر اساس ویژگیها و Data annotaions اعمالی، کار اعتبارسنجی را انجام داده و نتیجه را بازگشت دهیم.
خلاصهی تمام این اعمال و کلاسها، در کلاس پایه DataErrorInfoBase این قالب پروژه قرار گرفتهاند. بنابراین تنها کاری که باید صورت گیرد، مشتق کردن کلاس مدل مورد نظر از آن میباشد.
همچنین باید دقت داشت که نمایش اطلاعات خطاهای حاصل از اعتبارسنجی در این قالب پروژه بر اساس امکانات قالب متروی MahApps.Metro انجام میگیرد (این مورد از Silverlight toolkit به ارث رسیده است) و در حالت کلی خودکار نیست؛ اما در اینجا نیازی به کدنویسی اضافهتری ندارد.
به علاوه باید دقت داشت که این مورد ویژه را باید بر اساس آخرین Build کتابخانه MahApps.Metro که بهروزتر است دریافت و استفاده کرد. در اینجا با پارامتر Pre ذکر شده است.
PM> Install-Package MahApps.Metro -Pre
Here’s a summary of what’s new in this preview release:
Servers & middleware
Antiforgery middleware
API authoring
Antiforgery integration for minimal APIs
Native AOT
Request Delegate Generator supports interceptors feature
Full TrimMode is used for web projects compiled with trimming enabled
WebApplication.CreateEmptyBuilder
Blazor
Antiforgery integration
Server-side form handling improvements
Auto render mode
Register root-level cascading values
Improved integration of interactive components with server-side rendering
New EmptyContent parameter for Virtualize
Identity
New bearer token authentication handler
New API endpoints
Single page apps (SPA)
New Visual Studio templates
Here’s a summary of what’s new in this preview release:
- Improved startup debugging experience
- Blazor
- Form model binding & validation with server-side rendering
- Enhanced page navigation & form handling
- Preserve existing DOM elements with streaming rendering
- Specify component render mode at the call site
- Interactive rendering with Blazor WebAssembly
- Sections improvements
- Cascade query string values to Blazor components
- Blazor Web App template option for enabling server interactivity
- Blazor template consolidation
- Metrics
- Testing metrics in ASP.NET Core apps
- New, improved, and renamed counters
- API authoring
- Complex form binding support in minimal APIs
- Servers & middleware
- HTTP.sys kernel response buffering
- Redis-based output-cache
Here’s a summary of what’s new in this preview release:
- Improved ASP.NET Core debugging experience
- Servers & middleware
-
IHttpSysRequestTimingFeature
- SNI hostname in
ITlsHandshakeFeature
-
IExceptionHandler
-
- Blazor
- New Blazor Web App project template
- Blazor router integration with endpoint routing
- Enable interactivity for individual components with Blazor Server
- Improved packaging of Webcil files
- Blazor Content Security Policy (CSP) compatibility
- API authoring
- Support for generic attributes
- SignalR
- SignalR seamless reconnect
- Native AOT
- Support for
AsParameters
and automatic metadata generation in compile-timed generated minimal APIs
- Support for
- Authentication and authorization
- Authentication updates in ASP.NET Core SPA templates
- New analyzer for recommended
AuthorizationBuilder
usage
.NET 7 Release Candidate 1 (RC1) is now available and includes many great new improvements to ASP.NET Core.
Here’s a summary of what’s new in this preview release:
- Dynamic authentication requests in Blazor WebAssembly
- Handle location changing events
- Blazor WebAssembly debugging improvements
- .NET WebAssembly build tools for .NET 6 projects
- .NET JavaScript interop on WebAssembly
- Kestrel full certificate chain improvements
- Faster HTTP/2 uploads
- HTTP/3 improvements
- Experimental Kestrel support for WebTransport over HTTP/3
- Experimental OpenAPI support for gRPC JSON transcoding
- Rate limiting middleware improvements
- macOS dev-certs improvements