کتابخانهی iTextSharp 5.1.2 هفتهی قبل منتشر شده و ... من هر چقدر سایتی، بلاگی جایی را جستجو کردم که خلاصهای از تغییرات انجام شده آنرا گزارش دهد، چیزی نیافتم. ولی خوب، مطابق روال متداول کتابخانههای سورس باز، حداقل میتوان به change log مرتبط با سورس کنترل آنها مراجعه کرد. مثلا:
البته این هم خوب است ولی ایکاش میشد مثلا یک فید هم از این تغییرات تهیه کرد. یک سری از سایتهای هاستینگ مثل CodePlex و GitHub یک چنین فیدهایی را دارند. اما به نظر SourceForge از این لحاظ اندکی ضعیف است.
سایت روسی زیر میتواند با گرفتن آدرس یک مخزن کد SVN (برای مثال: https://itextsharp.svn.sourceforge.net/svnroot/itextsharp/trunk/ ) یک فید RSS از آن تهیه کند:
در همین راستا برنامهی CommitMonitor هم موجود است.
کتابخانهی iTextSharp 1.5.2 هفتهی قبل منتشر شده و ... من هر چقدر سایتی، بلاگی جایی را جستجو کردم که خلاصهای از تغییرات انجام شده آنرا گزارش دهد، چیزی نیافتم. ولی خوب، مطابق روال متداول کتابخانههای سورس باز، حداقل میتوان به change log مرتبط با سورس کنترل آنها مراجعه کرد. مثلا:
البته این هم خوب است ولی ایکاش میشد مثلا یک فید هم از این تغییرات تهیه کرد. یک سری از سایتهای هاستینگ مثل CodePlex و GitHub یک چنین فیدهایی را دارند. اما به نظر SourceForge از این لحاظ اندکی ضعیف است.
سایت روسی زیر میتواند با گرفتن آدرس یک مخزن کد SVN (برای مثال: https://itextsharp.svn.sourceforge.net/svnroot/itextsharp/trunk/ ) یک فید RSS از آن تهیه کند:
در همین راستا برنامهی CommitMonitor هم موجود است.
نیاز به درایور OleDB مخصوص بانکهای اطلاعاتی قدیمی
برای کار با بانکهای اطلاعاتی قدیمی از طریق ADO.NET، نیاز است بتوان به نحوی با آنها ارتباط برقرار کرد و اینکار از طریق استاندارد OleDB که صرفا مختص به ویندوز است، قابل انجام است. برای مثال برای کار با فاکسپرو نیز در ابتدا باید درایور OleDB آنرا نصب کرد که ... هیچکدام از لینکهای قدیمی مایکروسافت در این زمینه دیگر وجود خارجی ندارند! آخرین نگارش مرتبط را میتوانید در این آدرس و ذیل نام VFPOLEDBSetup.msi دریافت کنید (نگارش 9 را نصب میکند).
نیاز به دریافت بستهی System.Data.OleDb
در اولین قدم جهت کار با درایور OleDB نصب شده، باید یک اتصال را توسط نمونه سازی شیء OleDbConnection ایجاد کرد که ... این شیء هم شناسایی نمیشود. به همین جهت باید بستهی نیوگت مرتبط با آنرا به صورت جداگانهای دریافت و نصب کرد:
<ItemGroup> <PackageReference Include="System.Data.OleDb" Version="7.0.0"/> </ItemGroup>
برنامهی مبتنی بر درایور OleDB فاکسپرو اجرا نمیشود!
اولین سعی در برقراری ارتباط با درایور OleDB نصب شده، با خطای زیر خاتمه مییابد:
The 'VFPOLEDB' provider is not registered on the local machine.
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <PlatformTarget>x86</PlatformTarget> </PropertyGroup>
روش یافتن نام پروایدر OleDB نصب شده
رشتههای اتصالی OleDB، با =Provider، شروع میشوند. اکنون این سؤال مطرح میشود که پس از نصب VFPOLEDBSetup.ms یاد شده، دقیقا چه پروایدری به سیستم اضافه شدهاست و نام آن چیست؟
برای اینکار میتوان از چندسطر زیر برای یافتن نام تمام پروایدرهای OleDB نصب شدهی بر روی سیستم استفاده کرد:
var oleDbEnumerator = new OleDbEnumerator(); using var elements = oleDbEnumerator.GetElements(); foreach (DataRow row in elements.Rows) { Console.WriteLine($"{row["SOURCES_DESCRIPTION"]}: {row["SOURCES_NAME"]}"); }
Microsoft OLE DB Provider for SQL Server: SQLOLEDB MSDataShape: MSDataShape SQL Server Native Client 11.0: SQLNCLI11 Microsoft OLE DB Provider for Visual FoxPro: VFPOLEDB OLE DB Provider for Microsoft Directory Services: ADsDSOObject Microsoft OLE DB Driver for SQL Server: MSOLEDBSQL Microsoft OLE DB Driver for SQL Server Enumerator: MSOLEDBSQL Enumerator SQL Server Native Client 11.0 Enumerator: SQLNCLI11 Enumerator Microsoft OLE DB Provider for Search: Windows Search Data Source Microsoft OLE DB Provider for ODBC Drivers: MSDASQL Microsoft OLE DB Enumerator for ODBC Drivers: MSDASQL Enumerator Microsoft OLE DB Provider for Analysis Services 14.0: MSOLAP Microsoft OLE DB Provider for Analysis Services 14.0: MSOLAP Microsoft Jet 4.0 OLE DB Provider: Microsoft.Jet.OLEDB.4.0 Microsoft OLE DB Enumerator for SQL Server: SQLOLEDB Enumerator Microsoft OLE DB Simple Provider: MSDAOSP Microsoft OLE DB Provider for Oracle: MSDAORA
Microsoft OLE DB Provider for Visual FoxPro: VFPOLEDB
روش خواندن اطلاعات یک بانک اطلاعاتی فاکس پرو
پس از این مقدمات و تنظیمات، اکنون میتوانیم از قطعه کد متداول ADO.NET زیر، جهت خواندن اطلاعات یک بانک اطلاعاتی فاکسپرو، استفاده کنیم:
var connectionString = "Provider=VFPOLEDB;Data Source=" + @"C:\path\Db.DBF;Password=;Collating Sequence=MACHINE"; using var dbConnection = new OleDbConnection(connectionString); using var dataAdapter = new OleDbDataAdapter("select family from Db.DBF", dbConnection); using var dataset = new DataSet(); dataAdapter.Fill(dataset, "table1"); var sb = new StringBuilder(); foreach (DataRow dataRow in dataset.Tables[0].Rows) { var iranSystem = dataRow[0] as string; var unicode = iranSystem.FromIranSystemToUnicode(); if (!string.IsNullOrWhiteSpace(unicode)) { sb.AppendLine($"[DataRow(\"{iranSystem}\", \"{unicode}\")]"); } }
- نام پروایدر در رشته اتصالی، به VFPOLEDB تنظیم شدهاست.
- select انجام شده بر روی نام فایل dbf انجام میشود. یعنی هر فایل dbf، یک جدول را تشکیل میدهد.
- اگر نام فیلدهای موجود را نمیدانید، بجای select family از * select استفاده کنید و سپس بر روی DataSet پر شده، یک break-point را قرار دهید تا بتوانید نام تمام ستونها را از آن استخراج کنید.
- رشتهای را که توسط درایور فاکسپرو دریافت میکنید، یک رشتهی اسکی سیستم عامل داس است که در دات نت، با encoding مساوی 1252 شناخته میشود. یعنی encoding این رشتهی دریافتی، یونیکد پیشفرض داتنت نیست و باید توسط متد Encoding.GetEncoding(1252).GetBytes پردازش شود. که در نگارشهای جدید دات نت، این کدپیجها به صورت پیشفرض مهیا نیستند و باید در ابتدا ثبت شوند تا قابل استفاده شوند:
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance)
پیشنیازهای کار با کش توزیع شدهی مبتنی بر SQL Server
برای کار با کش توزیع شدهی با قابلیت ذخیره سازی در یک بانک اطلاعاتی SQL Server، نیاز است دو بستهی ذیل را به فایل project.json برنامه اضافه کرد:
{ "dependencies": { "Microsoft.Extensions.Caching.SqlServer": "1.1.0" }, "tools": { "Microsoft.Extensions.Caching.SqlConfig.Tools": "1.1.0-preview4-final" } }
ایجاد جدول ذخیره سازی اطلاعات کش توزیع شده به کمک ابزار sql-cache
پس از افزودن و بازیابی ارجاعات فوق، با استفاده از خط فرمان، به پوشهی جاری برنامه وارد شده و دستور ذیل را صادر کنید:
dotnet sql-cache create "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=sql_cache;Integrated Security=True;" "dbo" "AppSqlCache"
- در اینجا میتوان هر نوع رشتهی اتصالی معتبری را به انواع و اقسام بانکهای SQL Server ذکر کرد. برای نمونه در مثال فوق این رشتهی اتصالی به یک بانک اطلاعاتی از پیش ایجاد شدهی LocalDB اشاره میکند. نام دلخواه این بانک اطلاعاتی در اینجا sql_cache ذکر گردیده و نام دلخواه جدولی که قرار است این اطلاعات را ثبت کند AppSqlCache تنظیم شدهاست و dbo، نام اسکیمای جدول است:
در اینجا تصویر ساختار جدولی را که توسط ابزار dotnet sql-cache ایجاد شدهاست، مشاهده میکنید. اگر خواستید این جدول را خودتان دستی ایجاد کنید، یک چنین کوئری را باید بر روی دیتابیس مدنظرتان اجرا نمائید:
CREATE TABLE AppSqlCache ( Id NVARCHAR (449) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL, Value VARBINARY (MAX) NOT NULL, ExpiresAtTime DATETIMEOFFSET NOT NULL, SlidingExpirationInSeconds BIGINT NULL, AbsoluteExpiration DATETIMEOFFSET NULL, CONSTRAINT pk_Id PRIMARY KEY (Id) ); CREATE NONCLUSTERED INDEX Index_ExpiresAtTime ON AppSqlCache(ExpiresAtTime);
ایجاد جدول ذخیره سازی اطلاعات کش توزیع شده به کمک ابزار Migrations در EF Core
زیر ساخت کش توزیع شدهی مبتنی بر SQL Server هیچگونه وابستگی به EF Core ندارد و تمام اجزای آن توسط Async ADO.NET نوشته شدهاند. اما اگر خواستید قسمت ایجاد جدول مورد نیاز آنرا به ابزار Migrations در EF Core واگذار کنید، روش کار به صورت زیر است:
- ابتدا یک کلاس دلخواه جدید را با محتوای ذیل ایجاد کنید:
public class AppSqlCache { public string Id { get; set; } public byte[] Value { get; set; } public DateTimeOffset ExpiresAtTime { get; set; } public long? SlidingExpirationInSeconds { get; set; } public DateTimeOffset? AbsoluteExpiration { get; set; } }
public class MyDBDataContext : DbContext { public virtual DbSet<AppSqlCache> AppSqlCache { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<AppSqlCache>(entity => { entity.ToTable(name: "AppSqlCache", schema: "dbo"); entity.HasIndex(e => e.ExpiresAtTime).HasName("Index_ExpiresAtTime"); entity.Property(e => e.Id).HasMaxLength(449); entity.Property(e => e.Value).IsRequired(); }); } }
البته این مورد به شرطی است که بخواهید از یک دیتابیس، هم برای برنامه و هم برای ذخیره سازی اطلاعات کش استفاده کنید.
معرفی تنظیمات رشتهی اتصالی و نام جدول ذخیره سازی اطلاعات کش به برنامه
پس از ایجاد جدول مورد نیاز جهت ذخیره سازی اطلاعات کش، اکنون نیاز است این اطلاعات را به برنامه معرفی کرد. برای این منظور به کلاس آغازین برنامه مراجعه کرده و متد الحاقی AddDistributedSqlServerCache را بر روی مجموعهی سرویسهای موجود فراخوانی کنید؛ تا سرویسهای این کش توزیع شده نیز به برنامه معرفی شوند:
public void ConfigureServices(IServiceCollection services) { services.AddDistributedSqlServerCache(options => { options.ConnectionString = @"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=sql_cache;Integrated Security=True;"; options.SchemaName = "dbo"; options.TableName = "AppSqlCache"; });
آزمایش کش توزیع شدهی تنظیمی با فعال سازی سشنها
سشنها را همانند نکات ذکر شدهی در مطلب «ارتقاء به ASP.NET Core 1.0 - قسمت 16 - کار با Sessions» فعال کنید و سپس مقداری را در آن بنویسید:
public IActionResult Index() { HttpContext.Session.SetString("User", "VahidN"); return Json(true); } public IActionResult About() { var userContent = HttpContext.Session.GetString("User"); return Json(userContent); }
همانطور که مشاهده میکنید، سیستم سشن اینبار بجای حافظه، به صورت خودکار از جدول بانک اطلاعاتی SQL Server تنظیم شده، برای ذخیره سازی اطلاعات خود استفاده کردهاست.
کار با کش توزیع شده از طریق برنامه نویسی
همانطور که در مقدمهی بحث نیز عنوان شد، استفادهی از زیر ساخت کش توزیع شده منحصر به استفادهی از آن جهت ذخیره سازی اطلاعات سشنها نیست و از آن میتوان جهت انواع و اقسام سناریوهای مختلف مورد نیاز استفاده کرد. در این حالت روش دسترسی به این زیر ساخت، از طریق اینترفیس IDistributedCache است. زمانیکه متد AddDistributedSqlServerCache را فراخوانی میکنیم، در حقیقت کار ثبت یک چنین سرویسی به صورت خودکار انجام خواهد شد:
services.Add(ServiceDescriptor.Singleton<IDistributedCache, SqlServerCache>());
در اینجا یک نمونه از این تزریق وابستگی و سپس استفادهی از متدهای Set و Get اینترفیس IDistributedCache را مشاهده میکنید:
using System; using System.Text; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Distributed; namespace Core1RtmEmptyTest.Controllers { public class CacheTestController : Controller { readonly IDistributedCache _cache; public CacheTestController(IDistributedCache cache) { _cache = cache; } public IActionResult SetCacheData() { var time = DateTime.Now.ToLocalTime().ToString(); var cacheOptions = new DistributedCacheEntryOptions { AbsoluteExpiration = DateTime.Now.AddYears(1) }; _cache.Set("Time", Encoding.UTF8.GetBytes(time), cacheOptions); return View(); } public IActionResult GetCacheData() { var time = Encoding.UTF8.GetString(_cache.Get("Time")); ViewBag.data = time; return View(); } public bool RemoveCacheData() { _cache.Remove("Time"); return true; } } }
Value VARBINARY (MAX) NOT NULL,
public byte[] Value { get; set; }
در این حالت اگر برنامه را اجرا و مسیر http://localhost:7742/CacheTest/SetCacheData را فراخوانی کنیم، اطلاعات ذخیره شدهی با کلید Test را میتوان در بانک اطلاعاتی مشاهده کرد:
Tag helper مخصوص کش توزیع شده
در ASP.NET Core، میتوان از یک Tag Helper جدید به نام distributed-cache برای کش سمت سرور توزیع شدهی محتوای قسمتی از یک View به نحو ذیل استفاده کرد:
<distributed-cache name="MyCacheItem2" expires-sliding="TimeSpan.FromMinutes(30)"> <p>From distributed-cache</p> @DateTime.Now.ToString() </distributed-cache>
در اینجا name به صورت هش شده به صورت کلید کش مورد استفاده قرار میگیرد. سپس محتوای تگ distributed-cache رندر شده، تبدیل به آرایهای از بایتها گردیده و در بانک اطلاعاتی ذخیره میگردد.
ذکر name در اینجا اجباری است و باید دقت داشت که چون به عنوان کلید بازیابی کش مورد استفاده قرار خواهد گرفت، نباید به اشتباه در قسمتهای دیگر برنامه با همین نام وارد شود. در غیر اینصورت دو قسمتی که name یکسانی داشته باشند، یک محتوا را نمایش خواهند داد.
- قابلیت ترسیم اشیا روی بوم گرافیکی دلخواه
- قابلیت جابجایی اشیا
- قابلیت تغییر رنگ اشیا
- ترسیم اشیا توپر و تو خالی
- تعیین پهنای خط شی ترسیم شده
- تعیین رنگ پس زمینه در صورت تو پر بودن شی
- قابلیت پیش نمایش رسم شکل در زمان ترسیم اشیا
- توانایی انتخاب اشیا
- تعیین عمق شی روی بوم گرافیکی مورد نظر
- ترسیم اشیایی مانند خط، دایره، بیضی، مربع، مستطیل، لوزی، مثلث
- قابلیت تغییر اندازه اشیا ترسیم شده
خوب برای شروع ابتدا یک پروژه از نوع Windows Application ایجاد میکنیم (البته برای این قسمت میتوانیم یک پروژه Class Library ایجاد کنیم)
سپس یک پوشه به نام Models به پروزه اضافه نمایید.
خوب در این پروژه یک کلاس پایه به نام Shape در نظر میگیریم.
همه اشیا ما دارای نقطه شروع، نقطه پایان، رنگ قلم، حالت انتخاب، رنگ پس زمینه، نوع شی، .... میباشند که بعضی از خصوصیات را توسط خصوصیات دیگر محاسبه میکنیم. مثلا خاصیت Width و Height و X و Y توسط خصوصیات نقطه شروع و پایان میتوانند محاسبه شوند.
ساختار کلاسهای پروزه ما به صورت زیر است که مرحله به مرحله کلاسها پیاده سازی خواهند شد.
با توجه به تصویر بالا (البته این تجزیه تحلیل شخصی من بوده و دوستان به سلیقه خود ممکن است این ساختار را تغییر دهند)
نوع شمارشی ShapeType: در این نوع شمارشی انواع شیهای موجود در پروژه معرفی شده است
محتوای این نوع به صورت زیر تعریف شده است:
namespace PWS.ObjectOrientedPaint.Models { /// <summary> /// Shape Type in Paint /// </summary> public enum ShapeType { /// <summary> /// هیچ /// </summary> None = 0, /// <summary> /// خط /// </summary> Line = 1, /// <summary> /// مربع /// </summary> Square = 2, /// <summary> /// مستطیل /// </summary> Rectangle = 3, /// <summary> /// بیضی /// </summary> Ellipse = 4, /// <summary> /// دایره /// </summary> Circle = 5, /// <summary> /// لوزی /// </summary> Diamond = 6, /// <summary> /// مثلث /// </summary> Triangle = 7, } }
بهتر است وارد عمل شویم و ببینیم این سیستم چگونه عمل میکند. برای شروع ما خود Asp .net را به عنوان میزبان در نظر میگیریم.
- یک پروژه خالی Asp .net ایجاد کنید. (Asp .net Empty Web Application)
- وارد خط فرمان Package Manager شوید و عبارت زیر را وارد کنید:
یک کلاس به پروژه اضافه کنید و نام آن را TestModule بگذارید.
در متن کلاس عبارات زیر را تایپ کنید:
public class TestModule : NancyModule { public TestModue() { Get["/"] = x => "Welcome to my site!"; Get["/Hello/"] = x=> "Hello Nancy!"; Get["/Bye/{name}"] = x=> "Good bye " + x.name; } }
حال کلید F5 را زده و برنامه را اجرا کنید.
حالا در مرورگر خودتان عبارت http://localhost:12345/Hello را تایپ کنید. توجه کنید که به جای 12345 باید شماره پورتی که وب سرور دات نت اجراست تایپ کنید.
همانطور که متوجه شدید ما در خطوط بالا تعیین کرده ایم که برای درخواستهای از نوع Get که مسیر ریشه سایت را درخواست میکنند عبارت Welcome to my site! ارسال شود. همچنین برای درخواست هایی که مسیر /Hello را درخواست میکنند عبارت Hello Nancy نمایان میشود.
نکته جالب برای درخواستهای /Bye است. در اینجا ما یک پارامتر به نام name تعریف کرده ایم و گفته ایم که درخواستهای Bye که در ادامه آنها عبارتی وجود دارد به صورت Good bye به همراه عبارت بازگردانده شوند.
همین عملیات برای درخواستهای Put و Head و سایر انواع درخواست وجود دارد.
برای اینکه درخواستها از مسیر خاصی فراخوانی شوند کافی است در هنگام اعلان سازنده کلاس ماژول، مسیر را تعیین کنید.
public class TestModule : NancyModule { public TestModule() : base("/test") { Get["/user"] = x=> "It is test for user"; } }
این درخواستها از مسیری شبیه این مسیر فراخوانی خواهند شد:
Get["/hello/{username}"] = x=> { // some code // ... // ... return "Hello, " + username; };
همچنین امکان بازگرداندن کدهای وضعیت به طور مستقیم وجود دارد.
Get["/user"] = x=> return 200;
و یا
Get["/user] = x=> return HttpStatusCode.OK;
همانطور که گفته شد امکان میزبانی پروژههای Nancy از داخل برنامههای دات نتی هم وجود دارد. در مقاله بعدی به این موضوع خواهیم پرداخت.
قبل از پاسخگویی به سؤال بالا، به یک سری مقدمات نیاز است:
وقتی یک کوئری به اس کیو ال ارسال میشود، چه اتفاقی رخ میدهد؟
وقتی یک کوئری ارسال میشود، تعدادی از پروسسها بر روی کوئری شروع به فعالیتهایی مانند مهیا نمودن دادههای بازگشتی، یا ذخیره سازی و ... میکنند.
پروسسها به دو دسته زیر تقسیم میشوند:
- پروسسهایی که در relational engine رخ میدهند
- پروسسهایی که در storage engine رخ میدهند
در
relational engine، هر کوئری pars شده و سپس بوسیله query optimizer
پردازش و پلن اجرایی (execution plan) آن که بفرمت باینری است، ایجاد میشود و
به storage engine ارسال میگردد. در storage engine پروسسهایی مانند قفل
گذاری، نگهداری ایندکسها و تراکنشها رخ میدهد. هنگامیکه اس کیو ال
سرور کوئری را دریافت مینمایند، آن را بلافاصله به relational engine ارسال
میکند. سپس نحو (syntax) آن بررسی میشود؛ این عمل query parsing نامیده
میشود. خروجی عملیات پارسر، یک ساختار درختی (query tree) است. این ساختار
درختی مشخص کننده مراحل لازم جهت اجرای کوئری ارائه شده میباشد.
اگر یک کوئری شامل DML نباشد (مانند ساخت جدول)، علمیات بهبود برروی آن صورت
نخواهد گرفت. ولی در صورتیکه کوئری ارسالی، DML باشد، درخت اشاره شده در
بالا به algebrizer فرستاده میشود که وظیفه آن تفسیر و بررسی کلیه نام
اشیاء، جداول و ستونهای اشاره شده در متن کوئری است. فرآیند algebrizer
بسیار مهم و حیاتی است؛ بدلیل اینکه در کوئری ممکن است اشاره کنندههایی به
اشیایی باشند که در بانک اطلاعاتی موجود نیست. خروجی algebrizer یک query
processor tree باینری است که به بهبود دهنده کوئری ارسال میگردد.
معرفی Query Optimizer (بهبود دهنده پرس و جو)
بهبود
دهنده، بهترین مسیر اجرای کوئری را مشخص میکند. این بهبود دهنده است که مشخص
میکند که اطلاعات بوسیله ایندکس دریافت شوند، یا اینکه از چه اتصالی استفاده
شود و الی آخر. این تصمیمات براساس محاسبات هزینههای (میزان پردازش لازم
cpu و I/O) پلن اجرایی صورت خواهد پذیرفت. بهمین دلیل به پلن cost-based نیز شناخته میشود.
هنگامیکه کوئری سادهای مانند دریافت اطلاعات از یک جدول، که بر روی آن
ایندکس گذاری انجام نشدهاست، ارسال شود، بهبود دهنده بجای مشخص نمودن یک
پلن مناسب بهینه، از یک پلن ساده (trivial) استفاده میکند. ولی برعکس در
صورتیکه کوئری trivial نباشد (یعنی مثلا کوئری به گونهای باشد که از
ایندکسها به شکل صحیحی استفاده شده باشند)، بهبود دهنده یک پلن مناسب را
براساس اطلاعات آماری مهیا شده در اس کیو ال سرور، تولید و انتخاب مینماید.
اطلاعات
آماری از ستونها و ایندکسها جمع آوری میشود. این اطلاعات شامل نحوه
توزیع داده، یکتایی و انتخاب شوندگی است. این اطلاعات توسط یک histogram
ارائه میشود. اگر اطلاعات آماری برای یک ستون و یا ایندکس وجود داشته
باشد، بهبود دهنده از آنها برای محاسبات خود استفاده خواهد کرد. اطلاعات
آماری بصورت خودکار برای تمام ایندکسها و یا هر ستونی که بشود بر روی آنها
where یا join نوشت، فراهم خواهد شد.
بهبود دهنده با مقایسه پلنها براساس بررسی تفاوتهای انواع joinها، چیدمان
مجدد ترتیب join و بررسی ایندکسهای مختلف و سایر فعالیتهای دیگر، پلن
مناسب را انتخاب و از آن استفاده میکند. در طی هر کدام از فعالیتهای
اشاره شده، زمان اجرای آنها نیز تخمین زده (estimated cost) خواهد شد و در
پایان، زمان کل تخمینی بدست خواهد آمد و بهبود دهنده از این زمان برای انتخاب
پلن مناسب بهره خواهد برد. باید توجه داشت که این زمان تقریبی است. زمانیکه بهبود دهنده پلن اجرایی انتخاب میکند، یک actual plan را ایجاد و در حافظه ذخیره
میشود؛ بنام plan cache. البته درصورتیکه پلن مشابه و بهینهتری وجود
نداشته باشد.
استفاده مجدد از پلن ها
تولید پلن هزینه بر است. بههمین دلیل اس کیوال سرور اقدام به ذخیره سازی و نگهداری آنها میکند تا بتواند از آنها مجددا استفاده نماید؛ البته تا جایی که مقدور باشد. هنگامیکه آنها تولید میشوند، در قسمتی از حافظه بنام plan cache ذخیره میشوند. به این عمل procedure cache نیز گفته میشود.
هنگامیکه کوئری به سرور ارسال میشود، بوسیله بهبود دهنده، یک estimated plan ایجاد
خواهد شد و قبل از اینکه به storage engine ارسال شود، بهبود دهنده estimated
plan را با actual execution planهای موجود در plan cache مقایسه میکند.
در صورتیکه یک actual plan را مطابق با estimated plan پیدا نماید، از آن مجدد
استفاده خواهد کرد. این استفاده مجدد به عدم تحمیل سربار اضافهای به سرور جهت
کوئریهای بزرگ و پیچیده که در زمان واحد، هزاران بار اجرا خواهند شد، منجر میشود.
هر پلن فقط یکبار در حافظه ذخیره خواهد شد. ولی در مواقعی با تشخیص
بهبود دهنده و هزینه پلن، یک کوئری میتواند پلن دیگری نیز داشته باشد.
بنابراین پلن دوم نیز با مجموعه عملیاتی متفاوت، جهت اجرای موازی (parallel
execution) برای یک کوئری ایجاد و در حافظه ذخیره میشود.
پلنهای اجرایی برای همیشه در حافظه باقی نخواهند ماند. پلنهای اجرایی دارای
طول عمری طبق فرمول حاصل ضرب هزینه، در تعداد دفعات میباشند. مثلاً پلنی با
هزینه 10 و تعداد دفعات اجرای 5، طول عمر 50 را خواهد داشت. پروسس lazywriter
که یک پروسس داخلی است وظیفه آزاد سازی تمام انواع کشها، از جمله پلن کش را دارد. این پروسس در بازههای مشخص، تمام اشیاء درون حافظه را بررسی کرده
و یک واحد از طول عمر آنها میکاهد.
در موارد زیر، یک پلن از حافظه پاک خواهد شد:
1. به حافظه بیشتری نیاز باشد
2. طول عمر پلن صفر شده باشد
جمله آخر، معمولا باعث ایجاد مشکل میشوند.
اگر optimizer تکست کوئری مشابهی را مشاهده نماید، ولی با پارامترهای متفاوت، به کش پلن مراجعه کرده و اگر در آن جا قرار داشت، از آن مجددا استفاده مینماید. این استفاده مجدد خوب است؛ اما درصورتیکه پارامتر ارسالی نال باشد چه اتفاقی رخ میدهد؟ جدول سفارشات محصول بسیار حجیم است و متاسفانه از پلنی که برای بازگشت 40 رکورد قبلا ایجاد شده، برای بازگشت این حجم بالای از رکوردها استفاده میشود که این کشنده است.
هیچ تضمینی وجود ندارد که از وقوع این اتفاق جلوگیری نمایید؛ اما میتوانید در هنگام توسعه، پروسیجر را شناسایی و نسبت به رفع آنها اقدام نمایید. ابتدا کش پلن را خالی نمایید و سپس پروسیجر را با مقادیر متفاوت، اجرا نمایید. در صورتیکه پلنهای متفاوتی مشاهده نمودید، این یک علامت هشدار است و میبایست نسبت به رفع آنها اقدام فوری نمایید.
- ساخت برنامههای دسکتاپ به صورت چندسکویی (ویندوز، لینوکس، مک)
- استفاده از HTML,CSS,JavaScript که طراحان وب در این زمینه با آن به آسانی ارتباط برقرار میکنند.
- قابلیت استفاده از کتابخانههای قدرتمند تحت وب چون Bootstrap,Jquery,Angular Js و ...
- متن باز و رایگان است.
D:\electron\test1>npm init
npm i electron-prebuilt --save-dev
لازم است در اینجا توضیحی کوتاه در مورد انواع وابستگیها داشته باشیم:
Dependencies این نوع از وابستگیها، بستههایی را نصب میکنند که شما از آنها در کدهایتان استفاده میکنید و در آینده به همراه پروژه کمپایل میشوند. به طور خودکار وقتی بستهای را به عنوان وابستگی معرفی میکنید، npm وابستههای آن بسته را به صورت درختی بررسی میکند و آنها را هم نصب میکند.
DevDependencies : این نوع از وابستگیهای برای کارهای دیباگینگ و ... است؛ مثل آزمون واحد و ... که نیازی نیست در کامپایل نهایی لحاظ گردند. اگر این نوع کتابخانهها را به جای devdependencies به dependencies ارسال کنید، اتفاق خاصی نمیافتد. ولی در حجم برنامهی نهایی شما تاثیرگذار خواهند بود.
PeerDependencies: این نوع وابستگیها برای معرفی بستههایی استفاده میشوند که در پلاگینهایی که استفاده میکنید تاثیر دارند. ممکن است پلاگینی نیاز به استفادهی از یک بسته را دارد، ولی آن را در کد، Require نکرده باشد (در مورد Require بعدا صحبت میکنیم). ولی برای اجرا نیاز به این بسته دارد. به همین دلیل از نسخهی 3 به بعد، به شما هشدار میدهد که این بستهها را نیز لحاظ کنید (تا نسخهی npm2 به طور خودکار نصب میشد). همچنین نسخه بندی این وابستگیها را نیز در نظر میگیرد. این حالت را میتوانید مانند پلاگینهای جیکوئری تصور کنید که نیاز است قبل از آنها، کتابخانهی جیکوئری صدا زده شود؛ در صورتی که در خود پلاگین، جی کوئری صدا زده نشده است.
ویرایشگر اتم
قبل از اینکه بخواهیم کدنویسی با هر زبانی را آغاز کنیم، عموما یک ادیتور مناسب را برای کارمان بر میگزینیم. الکترون نیازی به ادیتور خاصی ندارد و از Notepad گرفته تا هر ادیتور قدرتمند دیگری را میتوانید استفاده کنید. ولی ادیتور اتم Atom که توسط خود الکترون هم تولید شده است، برای استفاده رایج است. ویژوال استودیو هم در این زمینه بسیار خوب و قدرتمند ظاهر شده است و حاوی Intellisense هوشمندی است.
این ادیتور که با ظاهری جذاب، توسط تیم گیت هاب تولید شده است، یک ویرایشگر متن باز با قابلیت توسعه و تغییر پذیری بالاست و از بستههای Node.js پشتیانی میکند و به صورت داخلی مجهز به سیستم گیت میباشد. بیشتر فناوریهای استفاده شده در این ویرایشگر، رایگان بوده و دارای جامعهی بزرگ متن باز میباشند. از فناوریهای مورد استفادهی آن میتوان به الکترون، CoffeScript ، Node.js ,LESS و ... اشاره کرد. شعار سازندگان این ادیتور «یک ویرایشگر قابل هک برای قرن 21» میباشد.
برای پشتیبانی از زبانهای مختلف، حاوی تعدادی زیادی پلاگین پیش فرض است مانند روبی ، سی شارپ، PHP ,Git,Perl,C/C++, Go,Objective-C,YAML و ...
آغاز کدنویسی
بگذارید کدنویسی را شروع کنیم. اگر اتم را نصب کرده باشید، میتوانید با وارد کردن عبارت زیر، پروژه خود را در ادیتور باز کنید:
atom .
{ "name": "electron", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "electron ." }, "author": "", "license": "ISC" }
const electron = require('electron'); const {app} = electron; const {BrowserWindow} = electron;
let win; app.on('ready', function() { // Create the browser window. win = new BrowserWindow({ width: 800, height: 600 }); });
اکنون در کنسول مینویسیم:
npm start
برای اینکه اولین برنامه واقعا خالی نباشد و ظاهری به آن بدهیم، یک فایل html میسازیم و در callback رویداد ready، بعد از ساخت پنجره آن را صدا میزنیم:
win.loadURL(`file://${__dirname}/index.html`);
string htmlStr = "<h1>.Net Tips</h1>"; htmlStr.ClearHtmlTags();
image1.Resize(50, 80);
dropDownList1.Bind((List<Category>)categories, "Name", "Id");
- کلاس دربرگیرنده متد یا متدهای الحاقی باید Public و Static باشد.
- متد الحاقی باید Public و Static باشد.
- اولین پارامتر متد الحاقی باید با کلمه کلیدی this همراه باشد و این پارامتر اشاره به کلاسی دارد که متد جاری به آن الحاق (یا ضمیمه) خواهد شد.
public static class StringExtensions { /// <summary> /// Count all words in a given string /// </summary> /// <param name="input">string to begin with</param> /// <returns>int</returns> public static int WordCount(this string input) { var count = 0; try { // Exclude whitespaces, Tabs and line breaks var re = new Regex(@"[^\s]+"); var matches = re.Matches(input); count = matches.Count; } catch (Exception) { return -1; } return count; } }
var s = "i Love Dot Net Tips."; var wordCount = s.WordCount();