انتقال به asp.net core
در ASP.NET Core 2.1 بجای متدهای Html.Partial vs Html.RenderPartial, sync vs async برای رندر partial views میتوان از Tag helper جدید partial استفاده کرد:
<partial name="_ProductPartial" asp-for="@Model[i]" />
در متن آمده که EF Core به صورت پیش فرض ، Db Context را به صورت Scoped ثبت میکند. و نحوه تزریق از طریق سازنده کلاسها است. از طرفی اگر درست متوجه شده باشم در مستندات ماکروسافت هشدار داده شده که این مدل طول حیات را نباید از طریق سازنده تزریق کرد.
When using a scoped service in a middleware, inject the service into the Invoke or InvokeAsync method. Don't inject via constructor injection because it forces the service to behave like a singleton. For more information, see Write custom ASP.NET Core middleware.
همچنین شما گفتید که "سرویسهای Scoped در محدودهی درخواست، مانند Singleton عمل میکنند و شیء ساخته شده و وضعیت آن در بین تمامی سرویسهایی که به آن نیاز دارند، مشترک است. بنابراین باید به این نکته در هنگام تعریف سرویس به صورت Scoped ، توجه داشته باشید."
در پروژهای که روی آن کار میکنم (ASP.NET Core Razor Pages) یک کلاس validation هست که میخوام به عنوان یک سرویس به کلاس هر صفحه تزریق بشه. اگر امکانش هست توضیح بدید که بر اساس مواردی که در بالا آوردم و هدفی که دارم آیا بین حالات singleton و scoped فرقی وجود دارد؟
ممنون.
نکته: دقت کنید که تنها یک فولدر App_GlobalResources به هر پروزه میتوان افزود. همچنین در ریشه هر مسیر موجود در پروژه تنها میتوان یک فولدر Appp_LocalResources داشت. پس از افزودن هر یک از این فولدرهای مخصوص، منوی فوق به صورت زیر در خواهد آمد:
protected object GetLocalResourceObject(string resourceKey) protected object GetLocalResourceObject(string resourceKey, Type objType, string propName)
txtTest.Text = GetLocalResourceObject("txtTest.Text") as string;
protected object GetGlobalResourceObject(string className, string resourceKey) protected object GetGlobalResourceObject(string className, string resourceKey, Type objType, string propName)
TextBox1.Text = GetGlobalResourceObject("Resource1", "String1") as string;
public static object GetLocalResourceObject(string virtualPath, string resourceKey) public static object GetLocalResourceObject(string virtualPath, string resourceKey, CultureInfo culture)
txtTest.Text = HttpContext.GetLocalResourceObject("~/Default.aspx", "txtTest.Text") as string;
public static object GetGlobalResourceObject(string classKey, string resourceKey) public static object GetGlobalResourceObject(string classKey, string resourceKey, CultureInfo culture)
TextBox1.Text = HttpContext.GetGlobalResourceObject("Resource1", "String1") as string;
//------------------------------------------------------------------------------ // <auto-generated> // This code was generated by a tool. // Runtime Version:4.0.30319.17626 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // </auto-generated> //------------------------------------------------------------------------------ namespace Resources { using System; /// <summary> /// A strongly-typed resource class, for looking up localized strings, etc. /// </summary> // This class was auto-generated by the StronglyTypedResourceBuilder // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option or rebuild the Visual Studio project. [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Web.Application.StronglyTypedResourceProxyBuilder", "10.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resource1 { private static global::System.Resources.ResourceManager resourceMan; private static global::System.Globalization.CultureInfo resourceCulture; [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Resource1() { } /// <summary> /// Returns the cached ResourceManager instance used by this class. /// </summary> [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Resources.Resource1", global::System.Reflection.Assembly.Load("App_GlobalResources")); resourceMan = temp; } return resourceMan; } } /// <summary> /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. /// </summary> [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } set { resourceCulture = value; } } /// <summary> /// Looks up a localized string similar to String1. /// </summary> internal static string String1 { get { return ResourceManager.GetString("String1", resourceCulture); } } } }
TextBox1.Text = Resources.Resource1.String1;
- استفاده از Postman برای آزمایش یک برنامهی Web API
- استفاده از strest برای آزمایش یک برنامهی Web API
روش سومی هم برای انجام اینکار وجود دارد که به صورت توکار از زمان ارائهی ASP.NET Core 2.1 به همراه TestServer آزمایشی آن میسر شد. این روش در نگارش 3.1، با تغییر روش تعریف فایل program.cs، جهت سازگاری آن با آزمونهای یکپارچگی/آزمایش کل سیستم، بهبود یافتهاست که خلاصهای از آن را در این مطلب بررسی میکنیم.
آزمونهای یکپارچگی در ASP.NET Core
آزمونهای یکپارچگی، برخلاف آزمونهای واحد که عموما از اشیاء تقلیدی استفاده میکنند، دقیقا بر روی همان سیستمی که قرار است به کاربر نهایی ارائه شود، اجرا میشوند. به همین جهت تنظیمات اولیهی آنها کمی بیشتر است و همچنین زمان اجرای آنها نیز به علت وابستگی به بانک اطلاعاتی واقعی، فایل سیستم، شبکه و غیره، نسبت به آزمونهای واحد بیشتر است.
برای ایجاد آزمونهای یکپارچگی در برنامههای ASP.NET Core، حداقل سه مرحله باید طی شوند:
الف) ایجاد یک class library که ارجاعی را به پروژهی اصلی دارد. این پروژه حاوی آزمایشهای ما خواهد بود.
ب) راه اندازی یک هاست وب آزمایشی برای ارسال درخواستها به آن و دریافت پاسخهای نهایی.
ج) استفاده از یک test runner (انواع و اقسام فریم ورکهای unit testing) برای اجرای آزمایشها
ایجاد یک پروژهی کتابخانه برای هاست و اجرای آزمایشهای یکپارچگی
فرض کنید میخواهیم برای همان پروژهی ایجاد JWTها، آزمایش یکپارچگی بنویسیم. پس از ایجاد یک پروژهی کتابخانهی جدید که قرار است هاست آزمایشهای ما شود، نیاز است محتوای فایل csproj آنرا به صورت زیر تغییر داد:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netcoreapp3.1</TargetFramework> <NoWarn>RCS1090</NoWarn> </PropertyGroup> <ItemGroup> <ProjectReference Include="..\ASPNETCore2JwtAuthentication.WebApp\ASPNETCore2JwtAuthentication.WebApp.csproj" /> </ItemGroup> <ItemGroup> <None Include="..\ASPNETCore2JwtAuthentication.WebApp\appsettings.json" CopyToOutputDirectory="PreserveNewest" /> </ItemGroup> <ItemGroup> <Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c329}" /> </ItemGroup> <ItemGroup> <PackageReference Include="fluentassertions" Version="5.10.3" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.1.8" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" /> <PackageReference Include="MSTest.TestAdapter" Version="2.1.2" /> <PackageReference Include="MSTest.TestFramework" Version="2.1.2" /> </ItemGroup> </Project>
1) TargetFramework آن باید به netcoreapp تنظیم شود.
2) باید ارجاع مستقیمی به کل پروژهی نهایی WebApp در آن وجود داشته باشد. چون در ادامه میخواهیم فایل Program.cs آنرا برای راه اندازی یک هاست وب آزمایشی، فراخوانی کنیم.
3) بستهی نیوگتی که کار راه اندازی هاست وب آزمایشی را انجام میدهد، Microsoft.AspNetCore.Mvc.Testing نام دارد. این بسته، کار کپی فایلهای پروژهی اصلی و همچنین تنظیم مسیر پروژه را به این مسیر جدید نیز انجام میدهد.
4) روش افزودن بستههای MSTest را مشاهده میکنید.
5) همچنین جهت سادهتر شدن بررسی نتایج آزمونهای انجام شده میتوان از fluentassertions نیز استفاده کرد.
راه اندازی هاست وب آزمایشی جهت انجام آزمونهای واحد
پس از انجام تنظیمات ابتدایی پروژهی آزمون یکپارچگی، نیاز است یک WebApplicationFactory سفارشی را ایجاد کرد:
using ASPNETCore2JwtAuthentication.WebApp; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; namespace ASPNETCore2JwtAuthentication.IntegrationTests { public class CustomWebApplicationFactory : WebApplicationFactory<Program> { protected override IWebHostBuilder CreateWebHostBuilder() { var builder = base.CreateWebHostBuilder(); builder.ConfigureLogging(logging => { //TODO: ... }); return builder; } protected override void ConfigureWebHost(IWebHostBuilder builder) { builder.ConfigureTestServices(services => { // Don't run `IHostedService`s when running as a test services.RemoveAll(typeof(IHostedService)); }); } } }
در ادامه روش سفارشی سازی WebApplicationFactory را مشاهده میکنید. برای مثال اگر خواستید سرویسها و تنظیمات پیشفرض برنامهی اصلی را تغییر دهید میتوانید متد CreateWebHostBuilder را بازنویسی کنید و یا اگر خواستید سرویس جدیدی را اضافه و یا حذف کنید، میتوان متد ConfigureWebHost را بازنویسی کرد.
استفاده از WebApplicationFactory سفارشی، جهت ایجاد یک HttpClient
هدف اصلی از ایجاد CustomWebApplicationFactory نه فقط راه اندازی یک هاست وب سفارشی است، بلکه توسط متد CreateClient آن میتوان به یک HttpClient دسترسی یافت که قابلیت ارسال اطلاعات را به برنامهی وبی که در پشت صحنه راه اندازی میشود، دارا است. کار CustomWebApplicationFactory شبیه به راه اندازی dotnet run در پشت صحنهاست. در اینجا دیگر نیازی نیست تا اینکار را به صورت دستی انجام داد. به همین جهت چون برنامهی وب اصلی به نحو متداولی در پشت صحنه اجرا میشود، عموما راه اندازی آن که شامل تنظیمات اولیه و یا حتی ایجاد بانک اطلاعاتی است، کمی کند است و اگر قرار باشد هربار اینکار صورت گیرد، به آزمونهای بسیار کندی خواهیم رسید. به همین جهت میتوان یک کلاس singleton را برای مدیریت تک وهلهی نهایی HttpClient آن به صورت زیر ایجاد کرد:
using System; using System.Threading; using System.Net.Http; namespace ASPNETCore2JwtAuthentication.IntegrationTests { public static class TestsHttpClient { private static readonly Lazy<HttpClient> _serviceProviderBuilder = new Lazy<HttpClient>(getHttpClient, LazyThreadSafetyMode.ExecutionAndPublication); /// <summary> /// A lazy loaded thread-safe singleton /// </summary> public static HttpClient Instance { get; } = _serviceProviderBuilder.Value; private static HttpClient getHttpClient() { var services = new CustomWebApplicationFactory(); return services.CreateClient(); //NOTE: This action is very time consuming, so it should be defined as a singleton. } } }
نوشتن اولین آزمون یکپارچگی
پس از تنظیم هاست وب آزمایشی و ایجاد یک HttpClient از پیش تنظیم شده که به آن اشاره میکند، اکنون میتوان اولین آزمون یکپارچگی را به صورت زیر نوشت:
using System.Net.Http; using System.Net.Http.Headers; using System.Text; using System.Text.Json; using System.Threading.Tasks; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace ASPNETCore2JwtAuthentication.IntegrationTests { [TestClass] public class JwtTests { [TestMethod] public async Task TestLoginWorks() { // Arrange var client = TestsHttpClient.Instance; // Act var token = await doLoginAsync(client); // Assert token.Should().NotBeNull(); token.AccessToken.Should().NotBeNullOrEmpty(); token.RefreshToken.Should().NotBeNullOrEmpty(); } [TestMethod] public async Task TestCallProtectedApiWorks() { // Arrange var client = TestsHttpClient.Instance; // Act var token = await doLoginAsync(client); // Assert token.Should().NotBeNull(); token.AccessToken.Should().NotBeNullOrEmpty(); token.RefreshToken.Should().NotBeNullOrEmpty(); // Act const string protectedApiUrl = "/api/MyProtectedApi"; client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.AccessToken); var response = await client.GetAsync(protectedApiUrl); response.EnsureSuccessStatusCode(); // Assert var responseString = await response.Content.ReadAsStringAsync(); responseString.Should().NotBeNullOrEmpty(); var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; var apiResponse = JsonSerializer.Deserialize<MyProtectedApiResponse>(responseString, options); apiResponse.Title.Should().NotBeNullOrEmpty(); apiResponse.Title.Should().Be("Hello from My Protected Controller! [Authorize]"); } private static async Task<Token> doLoginAsync(HttpClient client) { const string loginUrl = "/api/account/login"; var user = new { Username = "Vahid", Password = "1234" }; var response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Post, loginUrl) { Content = new StringContent(JsonSerializer.Serialize(user), Encoding.UTF8, "application/json") }); response.EnsureSuccessStatusCode(); var responseString = await response.Content.ReadAsStringAsync(); responseString.Should().NotBeNullOrEmpty(); return JsonSerializer.Deserialize<Token>(responseString); } } }
- در هر آزمونی نیاز است در ابتدا به TestsHttpClient.Instance، که همان HttpClient ساخته شدهی توسط CustomWebApplicationFactory است، دسترسی یافت و همانطور که عنوان شد، دسترسی به وهلهای از HttpClient که به هاست وب آزمایشی برنامهی اصلی اشاره میکند، عموما بسیار زمانبراست و برای مثال در دو آزمایش نوشته شدهی در اینجا اگر قرا باشد هربار اینکار از صفر انجام شود، زمان به اتمام رسیدن این آزمایشها بسیار طولانی خواهد شد. به همین جهت طول عمر TestsHttpClient را singleton تعریف کردیم تا فقط یکبار کار برپایی وب سرور آزمایشی در پشت صحنه انجام شود.
- سپس مابقی کار، همان روش استاندارد کار با HttpClient است. در ابتدا درخواستی را به سمت سرور آزمایشی که در پشت صحنه در حال اجرا است، ارسال میکنیم. چون HttpClient دریافتی توسط CustomWebApplicationFactory تنظیم شدهاست، دیگر نیازی به ذکر آدرس پایهی وب سایت مانند https://localhost:5001 نیست و آدرسهای ذکر شدهی در اینجا، نسبی هستند. سپس محتوای Response دریافتی از سرور را جهت تکمیل آزمایشات، بررسی خواهیم کرد.
یک نکته: اگر OpenAPI را در برنامههای Web API فعال کنید، میتوان با استفاده از ابزارهای تولید کد، کدهای مرتبط با HttpClient را نیز به صورت خودکار تولید و سپس از آنها در اینجا استفاده کرد.
اجرای آزمونهای یکپارچگی نوشته شده
چون ظاهر این آزمونها با آزمونهای واحد MSTest یا هر فریم ورک مشابه دیگری یکسان است، میتوان از امکانات IDEها برای اجرای آنها استفاده کرد و یا حتی میتوان دستور dotnet test را نیز در ریشهی این پروژهی جدید برای اجرای تمام آزمونهای نوشته شده، اجرا کرد:
کدهای کامل این مطلب را در اینجا میتوانید مشاهده کنید.
NoSQL و مایکروسافت
1) Azure table storage
Azure table storage در حقیقت یک Key-value store ابری است و برای کار با آن از اینترفیس پروتکل استاندارد OData استفاده میشود. علت استفاده و طراحی یک سیستم Key-value store در اینجا، مناسب بودن اینگونه سیستمها جهت مقاصد عمومی است و به این ترتیب میتوان به بازه بیشتری از مصرف کنندگان، خدمات ارائه داد.
پیش از ارائه Azure table storage، مایکروسافت سرویس خاصی را به نام SQL Server Data Services که به آن SQL Azure نیز گفته میشود، معرفی کرد. این سرویس نیز یک Key-Value store است؛ هرچند از SQL Server به عنوان مخزن نگهداری اطلاعات آن استفاده میکند.
2) SQL Azure XML Columns
فیلدهای XML از سال 2005 به امکانات توکار SQL Server اضافه شدند و این نوع فیلدها، بسیاری از مزایای دنیای NoSQL را درون SQL Server رابطهای مهیا میسازند. برای مثال با تعریف یک فیلد به صورت XML، میتوان از هر ردیف به ردیفی دیگر، اطلاعات متفاوتی را ذخیره کرد؛ به این ترتیب امکان کار با یک فیلد که میتواند اطلاعات یک شیء را قبول کند و در حقیقت امکان تعریف اسکیمای پویا و متغیر را در کنار امکانات یک بانک اطلاعاتی رابطهای که از اسکیمای ثابت پشتیبانی میکند، میسر میشود. در این حالت در هر ردیف میتوان تعدادی ستون ثابت را با یک ستون XML با اسکیمای کاملا پویا ترکیب کرد.
همچنین SQL Server در این حالت قابلیتی را ارائه میدهد که در بسیاری از بانکهای اطلاعاتی NoSQL میسر نیست. در اینجا در صورت نیاز و لزوم میتوان اسکیمای کاملا مشخصی را به یک فیلد XML نیز انتساب داد؛ هر چند این مورد اختیاری است و میتوان یک un typed XML را نیز بکار برد. به علاوه امکانات کوئری گرفتن توکار از این اطلاعات را به کمک XPath ترکیب شده با T-SQL، نیز فراموش نکنید.
بنابراین اگر یکی از اهداف اصلی گرایش شما به سمت دنیای NoSQL، استفاده از امکان تعریف اطلاعاتی با اسکیمای متغیر و پویا است، فیلدهای نوع XML اس کیوال سرور را مدنظر داشته باشید.
یک مثال عملی: فناوری Azure Dev Fabric's Table Storage (نسخه Developer ویندوز Azure که روی ویندوزهای معمولی اجرا میشود؛ یک شبیه ساز خانگی) به کمک SQL Server و فیلدهای XML آن طراحی شده است.
3) SQL Azure Federations
در اینجا منظور از Federations در حقیقت همان پیاده سازی قابلیت Sharding بانکهای اطلاعاتی NoSQL توسط SQL Azure است که برای توزیع اطلاعات بر روی سرورهای مختلف طراحی شده است. به این ترتیب دو قابلیت Partitioning و همچنین Replication به صورت خودکار در دسترس خواهند بود. هر Partition در اینجا، یک SQL Azure کامل است. بنابراین چندین بانک اطلاعاتی فیزیکی، یک بانک اطلاعاتی کلی را تشکیل خواهند داد.
هرچند در اینجا Sharding (که به آن Federation member گفته میشود) و در پی آن مفهوم «عاقبت یک دست شدن اطلاعات» وجود دارد، اما درون یک Shard یا یک Federation member، مفهوم ACID پیاده سازی شده است. از این جهت که هر Shard واقعا یک بانک اطلاعاتی رابطهای است. اینجا است که مفهوم برنامههای Multi-tenancy را برای درک آن باید درنظر داشت. برای نمونه یک برنامه وب را درنظر بگیرید که قسمت اصلی اطلاعات کاربران آن بر روی یک Shard قرار دارد و سایر اطلاعات بر روی سایر Shards پراکنده شدهاند. در این حالت است که یک برنامه وب با وجود مفهوم ACID در یک Shard میتواند سریع پاسخ دهد که آیا کاربری پیشتر در سایت ثبت نام کرده است یا خیر و از ثبت نامهای غیرمجاز جلوگیری به عمل آورد.
در اینجا تنها موردی که پشتیبانی نشدهاست، کوئریهای Fan-out میباشد که پیشتر در مورد آن بحث شد. از این جهت که با نحوه خاصی که Sharding آن طراحی شده است، نیازی به تهیه کوئریهایی که به صورت موازی بر روی کلیه Shards برای جمع آوری اطلاعات اجرا میشوند، نیست. هر چند از هر shard با استفاده از برنامههای دات نت، میتوان به صورت جداگانه نیز کوئری گرفت.
4) OData
اگر به CouchDB و امکان دسترسی به امکانات آن از طریق وب دقت کنید، در محصولات مایکروسافت نیز این دسترسی REST API پیاده سازی شدهاند.
OData یک RESTful API است برای دسترسی به اطلاعاتی که به شکل XML یا JSON بازگشت داده میشوند. انواع و اقسام کلاینتهایی برای کار با آن از جاوا اسکریپت گرفته تا سیستمهای موبایل، دات نت و جاوا، وجود دارند. از این API نه فقط برای خواندن اطلاعات، بلکه برای ثبت و به روز رسانی دادهها نیز استفاده میشود. در سیستمهای جاری مایکروسافت، بسیاری از فناوریها، اطلاعات خود را به صورت OData دراختیار مصرف کنندگان قرار میدهند مانند Azure table storage، کار با SQL Azure از طریق WCF Data Services (جایی که OData از آن نشات گرفته شده)، Azure Data Market (برای ارائه فیدهایی از اطلاعات خصوصا رایگان)، ابزارهای گزارشگیری مانند SQL Server reporting services، لیستهای شیرپوینت و غیره.
به این ترتیب به بسیاری از قابلیتهای دنیای NoSQL مانند کار با اطلاعات JSON بدون ترک دنیای رابطهای میتوان دسترسی داشت.
5) امکان اجرای MongoDB و امثال آن روی سکوی کاری Azure
امکان توزیع MongoDB بر روی یک Worker role سکوی کاری Azure وجود دارد. در این حالت بانکهای اطلاعاتی این سیستمها بر روی Azure Blob Storage قرار میگیرند که به آنها Azure drive نیز گفته میشود. همین روش برای سایر بانکهای اطلاعاتی NoSQL نیز قابل اجرا است.
به علاوه امکان اجرای Hadoop نیز بر روی Azure وجود دارد. مایکروسافت به کمک شرکتی به نام HortonWorks نسخه ویندوزی Hadoop را توسعه دادهاند. HortonWorks را افرادی تشکیل دادهاند که پیشتر در شرکت یاهو بر روی پروژه Hadoop کار میکردهاند.
6) قابلیتهای فرا رابطهای SQL Server
الف) فیلدهای XML (که در ابتدای این مطلب به آن پرداخته شد). به این ترتیب میتوان به یک اسکیمای انعطاف پذیر، بدون از دست دادن ضمانت ACID رسید.
ب) فیلد HierarchyId برای ذخیره سازی اطلاعات چند سطحی. برای مثال در بانکهای اطلاعاتی NoSQL سندگرا، یک سند میتواند سند دیگری را در خود ذخیره کند و الی آخر.
ج) Sparse columns؛ ستونهای اسپارس تقریبا شبیه به Key-value stores عمل میکنند و یا حتی Wide column stores نیز با آن قابل مقایسه است. در اینجا هنوز اسکیما وجود دارد، اما برای نمونه علت استفاده از Wide column stores این نیست که واقعا نمیدانید ساختار دادههای مورد استفاده چیست، بلکه در این حالت میدانیم که در هر ردیف تنها از تعداد معدودی از فیلدها استفاده خواهیم کرد. به همین جهت در هر ردیف تمام فیلدها قرار نمیگیرند، چون در اینصورت تعدادی از آنها همواره خالی باقی میماندند. مایکروسافت این مشکل را با ستونهای اسپارس حل کرده است؛ در اینجا هر چند ساختار کلی مشخص است، اما مواردی که هر بار استفاده میشوند، تعداد محدودی میباشند. به این صورت SQL Server تنها برای ستونهای دارای مقدار، فضایی را اختصاص میدهد. به این ترتیب از لحاظ فیزیکی و ذخیره سازی نهایی، به همان مزیت Wide column stores خواهیم رسید.
د) FileStreams در اس کیوال سرور بسیار شبیه به پیوستهای سندهای بانکهای اطلاعاتی NoSQL سندگرا هستند. در اینجا نیز اطلاعات در فایل سیستم ذخیره میشوند اما ارجاعی به آنها در جداول مرتبط وجود خواهند داشت.
7) SQL Server Parallel Data Warehouse Edition
SQL PDW، نگارش خاصی از SQL Server است که در آن یک شبکه از SQL Serverها به صورت یک وهله منطقی SQL Server در اختیار برنامه نویسها قرار میگیرد.
این نگارش، از فناوری خاصی به نام MPP یا massively parallel processing برای پردازش کوئریها استفاده میکند. در اینجا همانند بانکهای اطلاعاتی NoSQL، یک کوئری به نود اصلی ارسال شده و به صورت موازی بر روی تمام نودها پردازش گردیده (همان مفهوم Map Reduce که پیشتر در مورد آن بحث شد) و نتیجه در اختیار مصرف کننده قرار خواهد گرفت. نکته مهم آن نیز در عدم نیاز به نوشتن کدی جهت رخ دادن این عملیات از طرف برنامه نویسها است و موتور پردازشی آن جزئی از سیستم اصلی است. تنها کافی است یک کوئری SQL صادر گردد تا نتیجه نهایی از تمام سرورها جمع آوری و بازگردانده شود.
این نگارش ویژه تنها به صورت یک Appliance به فروش میرسد (به صورت سخت افزار و نرم افزار باهم) که در آن CPUها، فضاهای ذخیره سازی اطلاعات و جزئیات شبکه به دقت از پیش تنظیم شدهاند.