ابتدا در SQL Management Studio (یا روشهای دیگر) اقدام به ایجاد رویه مینماییم.
Create Procedure dbo.PWS_GetDataCount AS BEGIN SELECT COUNT(*) FROM backupfile END
خوب تا اینجای کار هیچگونه مشکلی نیست، اما مواقعی پیش میآید که نمیخواهیم کسی به سورس این رویهها دسترسی داشته باشد، یا اینکه آنها را تغییر دهد، مثلا مواقعی که نرم افزار شما روی سایت مشتری اجرا شده و مشتری دسترسی به دیتابیس و رویههای آن دارد. در این مواقع میتوان در صورت لزوم این رویهها را فقط خواندنی کرد، یعنی حتی خود شما هم نمیتوانید رویه را ویرایش نمایید (پس دقت کنید). روال کار بدین گونه است:
Create Procedure dbo.PWS_GetDataCount2 --Parameters With Encryption AS BEGIN SELECT COUNT(*) FROM backupfile END
در واقع با نوشتن With Encryption قبل از AS میتوان رویه ذخیره شده را رمزگذاری کرد. پس از ایجاد این رویه همانگونه که در تصویر زیر مشاهده مینمایید این رویه شکل یک کلید بروی آن ظاهر شده و دیگر قابل ویرایش نیست (بهتر است رویههای خود را در زمان انتشار روی سیستم مقصد رمزگذاری نمایید).
دقت نمایید که استفاده از این عمل تاثیری در سرعت اجرای رویه ذخیره شده ندارد. البته روشهایی هم برای عکس این عمل وجود دارد که میتوانید از طریق این لینک به اطلاعات بیشتری دست پیدا کنید.
مرجع سریع کد کلیدهای صفحه کلید
public class Person { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } }
public class PeopleRepository { private List<Person> _people; public PeopleRepository() { _people = new List<Person> { new Person{ Id=1,Age=28,Name="Uthman"}, new Person{ Id=2,Age=27,Name="Vahid"}, new Person{ Id=3,Age=26,Name="Hadi"}, new Person{ Id=4,Age=25,Name="Saman"}, new Person{ Id=5,Age=20,Name="Sirwan"}, }; } public List<Person> GetAll() { return _people; } }
[Route("api/people")] public class PeopleController : Controller { PeopleRepository _repository; public PeopleController() { _repository = new PeopleRepository(); } [HttpGet("")] public IActionResult Get() { return Ok(_repository.GetAll()); } [HttpGet("{id:int}")] public IActionResult Get(int id) { return Ok(_repository.GetAll().FirstOrDefault(p => p.Id == id)); } [HttpPost] public IActionResult Post([FromBody]Person person) { return Ok(person); } [HttpPut("{id:int}")] public IActionResult Put(int id,[FromBody] Person person) { if (id != person.Id) return BadRequest(); return Ok(person); } [HttpDelete("{id:int}")] public IActionResult Delete(int id) { return Ok(); } [HttpPost("avatar")] public IActionResult Post(IFormFile file) { return Ok(); } }
GET http://localhost:59416/api/people
تا به اینجا توانستیم فقط با نوشتن آدرس API مورد نظر، آن را فراخوانی کنیم.
برای ارسال پارامترهایی در هدر درخواست فقط کافیست دقیقا در خط پایین آدرس، به صورت field-name:field-value، هر پارامتری را که میخواهید، به همراه درخواست ارسال کنید. برای نمونه برای API لیست افراد که در بالا تست کردیم، میتوانیم هدر را به صورت زیر تنظیم نماییم :
GET http://localhost:59416/api/people Content-Type: application/json
اجرای درخواست GET برای دریافت یک شخص خاص
GET http://localhost:59416/api/people/1
خروجی آن به صورت زیر میباشد
درخواست POST برای درج کاربر جدید:
POST http://localhost:59416/api/people content-type: application/json { "id": 10, "name": "ali", "age":37 }
بعد از هدرهای درخواست، یک خط خالی ایجاد کنید و پایینتر از خط خالی، میتوانید مقادیر body درخواست را وارد نمایید.
درخواست PUT برای آپدیت یک شخص :
PUT http://localhost:59416/api/people/3 content-type: application/json { "id": 3, "name": "ali", "age":37 }
درخواست DELETE برای حذف شخص:
DELETE http://localhost:59416/api/people/3 content-type: application/application/json
ارسال توکن اعتبارسنجی :
در صورتی که یک API نیاز به اعتبار سنجی دارد و باید توکن را به همراه درخواستی ارسال نمایید، میتوانید در هدر درخواست، همانند زیر، توکن را ارسال نمایید
GET http://localhost:59416/api/people content-type: application/json Authorization: Bearer token
آپلود فایل:
یکی از API هایی که در مثال ابتدای مقاله داشتیم، مربوط به آپلود فایل آواتار هست که از ورودی، یک IFormFile را به عنوان ورودی دریافت میکند. برای آپلود فایل به کمک افزونه Rest Client میتوانیم به صورت زیر فایل را ارسال نماییم
POST http://localhost:59416/api/people/avatar Content-Type: multipart/form-data; boundary=----MyBoundary ------MyBoundary Content-Disposition: form-data; name="file";filename="Studio" content-type: image/png < C:\Users\rahimi\Downloads\Studio.png ------MyBoundary--
قبل از آدرس فایل، وجود > ضروری میباشد.
فعال سازی دکمه Send Request به ازای هر آدرس:
اگر در یک فایل، چند آدرس را همانند عکس زیر داشته باشید، فقط یک دکمهی Send Request وجود خواهد داشت که کلیک بر روی آن منجر به فراخوانی اولین url میشود.
برای داشتن یک دکمه Send Request به ازای هر API، باید بین هر کدام از API ها، حداقل سه تا # قرار دهید.
### Get All People GET http://localhost:59416/api/people content-type: application/json ### Get Person GET http://localhost:59416/api/people/1 ### Create POST http://localhost:59416/api/people content-type: application/json { "id": 10, "name": "ali", "age":37 } ### Edit person PUT http://localhost:59416/api/people/3 content-type: application/json { "id": 3, "name": "ali", "age":37 } ### Delete person DELETE http://localhost:59416/api/people/3 content-type: application/application/json ### Upload Avatar POST http://localhost:59416/api/people/avatar Content-Type: multipart/form-data; boundary=----MyBoundary ------MyBoundary Content-Disposition: form-data; name="file";filename="Studio" content-type: image/png < C:\Users\rahimi\Downloads\Studio.png ------MyBoundary--
افزونهی Rest Client، فراتر از توضیحات این مقاله میباشد. در صورت علاقه و برای مطالعه بیشتر در مورد آن، میتوانید به لینک صفحه افزونه مراجعه نمایید.
ممنوع کردن استفادهی از ساختارهای دادهی غیرجنریک
قدم اول مواجه شدن با یک چنین کدهای قدیمی، ممنوع کردن استفادهی از ساختارهای دادهی غیرجنریک و الزام به تبدیل آنها به نوعهای جدید است. برای این منظور میتوان از Microsoft.CodeAnalysis.BannedApiAnalyzers استفاده کرد که توضیحات بیشتر آنرا در مطلب «غنی سازی کامپایلر C# 9.0 با افزونهها» پیشتر بررسی کردهایم. به صورت خلاصه، ابتدا بستهی نیوگت آنرا به صورت یک آنالایزر جدید به فایل csproj. برنامه معرفی میکنیم:
<Project Sdk="Microsoft.NET.Sdk"> <ItemGroup> <PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.3"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> </ItemGroup> <ItemGroup> <AdditionalFiles Include="$(MSBuildThisFileDirectory)BannedSymbols.txt" Link="Properties/BannedSymbols.txt"/> </ItemGroup> </Project>
# https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.BannedApiAnalyzers/BannedApiAnalyzers.Help.md T:System.Collections.ICollection;Don't use a non-generic data structure. T:System.Collections.Hashtable;Don't use a non-generic data structure. T:System.Collections.ArrayList;Don't use a non-generic data structure. T:System.Collections.SortedList;Don't use a non-generic data structure. T:System.Collections.Stack;Don't use a non-generic data structure. T:System.Collections.Queue;Don't use a non-generic data structure.
پیشنهاد یک دیکشنری کم دردسرتر!
برای نمونه پس از تنظیمات فوق، مجبور به تغییر تمام hash tableها به دیکشنریهای جدید جنریک خواهیم شد؛ اما ... اگر اینکار را انجام دهیم، برنامهای که تا پیش از این بدون مشکل کار میکرد، اکنون با استثناهای متعدد یافت نشدن کلیدها، خاتمه پیدا میکند! چون دیگر دیکشنریهای جدید، همانند hash tableهای قدیمی، در صورت عدم وجود کلیدی، نال را بازگشت نمیدهند.
برای رفع این مشکل و اصلاح انبوهی از کدها با حداقل تغییرات و عدم تکرار TryGetValueها در همهجا، میتوان دسترسی به ایندکسهای یک دیکشنری استاندارد دات نت را به صورت زیر با ارثبری از آن، بازنویسی کرد:
/// <summary> /// This custom IDictionary doesn't throw a KeyNotFoundException while accessing its value by a given key /// </summary> public interface INullValueDictionary<TKey, TValue> : IDictionary<TKey, TValue> { new TValue this[TKey key] { get; set; } } /// <summary> /// This custom IDictionary doesn't throw a KeyNotFoundException while accessing its value by a given key /// </summary> public class NullValueDictionary<TKey, TValue> : Dictionary<TKey, TValue>, INullValueDictionary<TKey, TValue> { public new TValue this[TKey key] { get => TryGetValue(key, out var val) ? val : default; set => base[key] = value; } }
ما میتوانیم بعد از ساخت جدول و انتشار مقداری داده در آن قیدهایی را ایجاد کنیم. بطور پیشفرض اگر شرط قید ما بر قرار بود قید به طور صحیح ساخته میشود و اگر شرط قید ما بر قرار نباشد قید با خطای conflict مواجه خواهد شد.
بطور کلی غیر فعال کردن قیدها کار درستی نیست. ولی در برخی مواقع برای تسریع در اجرای کد میتوانیم قید را غیر فعال کنیم. بطور مثال اگر یک میلیون داده قرار است در جدول درج شود و مطمئن هستیم که این دادهها جامعیت دادهها را حفظ میکنند آنگاه میتوانیم قید را برای تسریع در عمل درج بطور موفق غیر فعال کنیم.
فعال و غیر فعال کردن از طریق DDL
با غیر فعال کردن قیود دادهها را در وضعیت نامناسبی قرار میدهیم ولی همان طور که اشاره شد بطور موفق اشکالی پیش نخواهد آمد.
در ادامه ابتدا طریقه غیرفعال کردن و مجددا فعال کردن قیود را توسط دستور alter table نشان خواهم داد سپس به سراغ امکانات ویزاردی میرویم. ابتدا یک جدول تک ستونه ایجاد میکنیم:
CREATE TABLE testTable (column1 integer not null);
الان هیچ قیدی روی جدول لحاظ نشده است. پس هر داده که در رنج domain ستون باشد را میتوانیم درج کنیم. پس بطور نمونه این دادهها را درج میکنیم:
INSERT INTO testTable VALUES (-10), (0), (10), (20), (30), (40)
حالا تصمیم داریم قیدی روی ستون column1 بگذاریم که توسط آن تنها اعداد مثبت در جدول درج شوند. پس داریم:
ALTER TABLE testTable WITH CHECK ADD CONSTRAINT NoNegative CHECK (column1 > 0);
The ALTER TABLE statement conflicted with the CHECK constraint "NoNegative".
برای ساخت این قید روی این دادهها تنها راه استفاده از کلید واژههای WITH NOCHECK است یعنی:
ALTER TABLE testTable WITH NOCHECK ADD CONSTRAINT NoNegative CHECK (column1 > 0);
و اکنون سعی میکنیم یک مقدار منفی در جدول درج کنیم:
INSERT INTO testTable VALUES (-5) /* The INSERT statement conflicted with the CHECK constraint "NoNegative". */
اما قیدی که ساخته بودیم در جدول در حال اعمال شدن است. برای درج مقدار منفی باید غیر را غیر فعال کنیم.
ALTER TABLE TestTable NOCHECK CONSTRAINT NoNegative
و حالا مقدار منفی را درج میکنیم. و برای برگرداندن وضعیت NOCHECK به وضعیت CHECK باید از کلید واژههای WITH NOCHECK استفاده کنیم. چرا که داده هایی در جدول درج شده اند که قید مورد نظر ما را نقض میکنند.
ALTER TABLE TestTable WITH NOCHECK CHECK CONSTRAINT NoNegative
فعال و غیر فعال کردن از طریق design
در قسمت object explorer قید مورد نظر را پیدا کرده و روی آن راست کلیک کرده و گزینه Modify را انتخاب کنید. سپس در پنجره باز شده در قسمت Table Designer تغییرات مورد نظر خود را اعمال کنید.
تهیه یک بانک اطلاعاتی نمونه
برای نمایش امکانات کار با روش Database first، نیاز است یک بانک اطلاعاتی را به صورت مستقل و متداولی ایجاد کنیم. به همین جهت اسکریپت SQL ذیل را توسط Management studio اجرا کنید تا بانک اطلاعاتی BloggingCore2016، به همراه دو جدول به هم وابسته، در آن ایجاد شوند:
CREATE DATABASE [BloggingCore2016] GO USE [BloggingCore2016] GO CREATE TABLE [Blog] ( [BlogId] int NOT NULL IDENTITY, [Url] nvarchar(max) NOT NULL, CONSTRAINT [PK_Blog] PRIMARY KEY ([BlogId]) ); GO CREATE TABLE [Post] ( [PostId] int NOT NULL IDENTITY, [BlogId] int NOT NULL, [Content] nvarchar(max), [Title] nvarchar(max), CONSTRAINT [PK_Post] PRIMARY KEY ([PostId]), CONSTRAINT [FK_Post_Blog_BlogId] FOREIGN KEY ([BlogId]) REFERENCES [Blog] ([BlogId]) ON DELETE CASCADE ); GO INSERT INTO [Blog] (Url) VALUES ('https://www.dntips.ir/'), ('http://blogs.msdn.com/dotnet'), ('http://blogs.msdn.com/webdev'), ('http://blogs.msdn.com/visualstudio') GO
پیشنیازهای مهندسی معکوس ساختار بانک اطلاعاتی در EF Core
در قسمت اول در حین بررسی «برپایی تنظیمات اولیهی EF Core 1.0 در یک برنامهی ASP.NET Core 1.0»، چهار مدخل جدید را به فایل project.json برنامه اضافه کردیم. مدخل جدید Microsoft.EntityFrameworkCore.Tools که به قسمت tools آن اضافه شد، پیشنیاز اصلی کار با EF Core Migrations است. همچنین وجود مدخل Microsoft.EntityFrameworkCore.SqlServer.Design برای تدارک امکانات مهندسی معکوس ساختار یک بانک اطلاعاتی SQL Server ضروری است.
تبدیل ساختار دیتابیس BloggingCore2016 به کدهای معادل EF Core آن
پس از فعال سازی ابزارهای خط فرمان EF Core، به پوشهی اصلی پروژه مراجعه کرده، کلید shift را نگه دارید. سپس کلیک راست کرده و گزینهی Open command window here را انتخاب کنید تا خط فرمان از این پوشه آغاز شود. در ادامه دستور ذیل را صادر کنید:
dotnet ef dbcontext scaffold "Data Source=(local);Initial Catalog=BloggingCore2016;Integrated Security = true" Microsoft.EntityFrameworkCore.SqlServer -o Entities --context MyDBDataContext --verbose
اجرا این دستور سبب اتصال به رشتهی اتصالی ذکر شده که به بانک اطلاعاتی BloggingCore2016 اشاره میکند، میشود. سپس پروایدر مدنظر ذکر شدهاست. سوئیچ o محل درج فایلهای نهایی را مشخص میکند. برای مثال در اینجا فایلهای نهایی مهندسی معکوس شده در پوشهی Entities درج میشوند (تصویر فوق). همچنین در اینجا امکان ذکر فایل context تولیدی نیز وجود دارد. اگر علاقمند باشید تا تمام ریز جزئیات این عملیات را نیز مشاهده کنید، میتوانید پارامتر اختیاری verbose را نیز به انتهای دستور اضافه نمائید.
بقیه مراحل کار با این فایلهای تولید شده، با نکاتی که تاکنون عنوان شدهاند یکی است. برای مثال اگر میخواهید رشتهی اتصالی پیش فرض را از این Context تولید شده خارج کنید:
public partial class MyDBDataContext : DbContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer(@"Data Source=(local);Initial Catalog=BloggingCore2016;Integrated Security = true"); }
بررسی پارامترهای دیگر ابزار مهندسی معکوس به Code First
اگر دستور dotnet ef dbcontext scaffold --help را صادر کنیم، خروجی راهنمای ذیل را میتوان مشاهده کرد:
Usage: dotnet ef dbcontext scaffold [arguments] [options] Arguments: [connection] The connection string of the database [provider] The provider to use. For example, Microsoft.EntityFrameworkCore.SqlServer Options: -a|--data-annotations Use DataAnnotation attributes to configure the model where possible. If omitted, the output code will use only the fluent API. -c|--context <name> Name of the generated DbContext class. -f|--force Force scaffolding to overwrite existing files. Otherwise, the code will only proceed if no output files would be overwritten. -o|--output-dir <path> Directory of the project where the classes should be output. If omitted, the top-level project directory is used. --schema <schema> Selects a schema for which to generate classes. -t|--table <schema.table> Selects a table for which to generate classes. -e|--environment <environment> The environment to use. If omitted, "Development" is used. -h|--help Show help information -v|--verbose Enable verbose output
- حالت پیش فرض تنظیمات روابط مدلها در این روش، حالت استفاده از Fluent API است. اگر میخواهید آنرا به حالت استفادهی از Data Annotations تغییر دهید، پارامتر a- و یا data-annotations-- را در دستور نهایی ذکر کنید.
- حالت پیش فرض تولید فایلهای نهایی این روش، عدم بازنویسی فایلهای موجود است. اگر میخواهید پس از تغییر بانک اطلاعاتی، مجددا این فایلها را از صفر تولید کنید، پارامتر f- و یا force- را در دستور نهایی ذکر کنید.
بنابراین اگر میخواهید هربار فایلهای نهایی را بازنویسی کنید و همچنین روش کار با Data Annotations را ترجیح میدهید، دستور نهایی، شکل زیر را پیدا خواهد کرد:
dotnet ef dbcontext scaffold "Data Source=(local);Initial Catalog=BloggingCore2016;Integrated Security = true" Microsoft.EntityFrameworkCore.SqlServer -o Entities --context MyDBDataContext --verbose --force --data-annotations
کار با یک بانک اطلاعاتی موجود، با روش مهاجرتهای Code First
فرض کنید میخواهید از یک بانک اطلاعاتی از پیش موجود EF 6.x (یا هر بانک اطلاعاتی از پیش موجود دیگری)، به روش پیش فرض EF Core استفاده کنید. برای این منظور:
- ابتدا جدول migration history قدیمی آنرا حذف کنید؛ چون ساختار آن با EF Core یکی نیست.
- سپس با استفاده از دستور dotnet ef dbcontext scaffold فوق، معادل کلاسها، روابط و Context سازگار با EF Core آنرا تولید کنید.
- در ادامه رشتهی اتصالی پیش فرض آنرا از کلاس Context تولیدی خارج کرده و از یکی از روشهای مطرح شدهی در مطلب «شروع به کار با EF Core 1.0 - قسمت 1 - برپایی تنظیمات اولیه» استفاده کنید.
- سپس نیاز است این Context جدید را توسط متد services.AddDbContext به لیست سرویسهای برنامه اضافه کنید. این مورد نیز در قسمت اول بررسی شدهاست.
- مرحلهی بعد، افزودن جدول __EFMigrationsHistory جدید EF Core، به این بانک اطلاعاتی است. برای این منظور به روش متداول فعال کردن مهاجرتها، دستور ذیل را صادر کنید:
dotnet ef migrations add InitialDatabase
using Microsoft.EntityFrameworkCore.Migrations; namespace Core1RtmEmptyTest.DataLayer.Migrations { public partial class InitialDatabase : Migration { protected override void Up(MigrationBuilder migrationBuilder) { } protected override void Down(MigrationBuilder migrationBuilder) { } } }
سپس دستور به روز رسانی بانک اطلاعاتی را صادر کنید:
dotnet ef database update
پس از این مرحله، روش کار، Code first خواهد بود. برای مثال خاصیتی را به کلاسی اضافه میکنید و سپس دو دستور ذیل را صادر خواهید کرد که در آن v2 یک نام دلخواه است:
dotnet ef migrations add v2 dotnet ef database update
NOSQL قسمت سوم
در مطلب قبلی با نوع اول پایگاههایداده NoSQL یعنی Key/Value Store آشنا شدیم و در این مطلب به معرفی دسته دوم یعنی Document Database خواهیم پرداخت.
در این نوع پایگاه داده ، دادهها مانند نوع اول در قالب
کلید/مقدار ذخیره میشوند و بازگردانی مقادیر نیز دقیقا مشابه نوع اول یعنی Key/Value Store بر اساس کلید میباشد. اما
تفاوت این سیستم با نوع اول در دستهبندی دادههای مرتبط با یکدیگر در قالب یک Document میباشد. سعی کردم در این مطلب با ذکر مثال مطالب را شفافتر بیان کنم:
به عنوان مثال اگر بخواهیم جداول مربوط به پستهای یک سیستم CMS را بصورت رابطهای پیاده کنیم ، یکی از سادهترین حالات پایه برای پستهای این سیستم در حالت نرمال به صورت زیر میباشد.
جداول واضح بوده و نیازی به توضیح ندارد ، حال نحوهی ذخیرهسازی دادهها در سیستم Document Database برای چنین مثالی را بررسی میکنیم:
{ _id: ObjectID(‘4bf9e8e17cef4644108761bb’), Title: ‘NoSQL Part3’, url: ‘https://www.dntips.ir/yyy/xxxx’, author: ‘hamid samani’, tags: [‘databases’,’mongoDB’], comments:[ {user: ‘unknown user’, text:’unknown test’ }, {user:unknown user2’, text:’unknown text2 } ] }
همانگونه که مشاهد میکنید نحوهی ذخیرهسازی دادهها بسیار با سیستم رابطهای متفاوت میباشد ، با جمعبندی تفاوت نحوهی نگهداری دادهها در این سیستم و RDBMS و بررسی این سیستم نکات اصلی به شرح زیر میباشند:
۱-فرمت ذخیره سازی دادهها مشابه فرمت JSON میباشد.
۲-به مجموعه دادههای مرتبط به یکدیگر Document گفته میشود.
۳-در این سیستم JOIN ها وجود ندارند و دادههای مرتبط کنار یکدیگر قرار میگیرند ، و یا به تعریف دقیقتر دادهها در یک داکیومنت اصلی Embed میشوند.
به عنوان مثال در اینجا مقدار commentها برابر با آرایهای از Documentها میباشد.
۴-مقادیر میتوانند بصورت آرایه نیز در نظر گرفته شوند.
۵-در سیستمهای RDBMS در صورتی که بخواهیم از وجود JOINها صرفنظر کنیم. به عدم توانایی در نرمالسازی برخواهیم خورد که یکی از معایب عدم نرمالسازی وجود مقادیر Null در جداول میباشد؛ اما در این سیستم به دلیل Schema free بودن میتوان ساختارهای متفاوت برای Documentها در نظر گرفت.
به عنوان مثال برای یک پست میتوان مقدار n کامنت تعریف کرد و برای پست دیگر هیچ کامنتی تعریف نکرد.
۶-در این سیستم اصولا نیازی به تعریف ساختار از قبل موجود
نمیباشد و به محض اعلان دستور قرار دادن دادهها در پایگاهداده ساختار متناسب
ایجاد میشود.
با مقایسه دستورات CRUD در هر دو نوع پایگاه داده با نحوهی کوئری گرفتن از Document Database آشنا میشویم:
در SQL برای ایجاد جدول خواهیم داشت:
CREATE TABLE posts ( id INT NOT NULL AUTO_INCREMENT, author_id INT NOT NULL, url VARCHAR(50), PRIMARY KEY (id) )
دستور فوق در Document Database معادل است با:
db.posts.insert({id: “256” , author_id:”546”,url:"http://example.com/xxx"}) // با قرار دادن مقدار نوع ساختار مشخص میشود
در SQL جهت خواندن خواهیم داشت:
SELECT * from posts WHERE author_id > 100
db.posts.find({author_id:{$gt:”1000”}})
در SQL جهت بروزرسانی داریم:
UPDATE posts SET author_id= "123"
db.posts.update({ $set: { author_id: "123" }})
در SQL جهت حذف خواهیم داشت:
DELETE FROM posts WHERE author_id= "654"
که معادل است با:
db.posts.remove( { author_id: "654" } )
همانگونه که مشاهده میفرمایید نوشتن کوئری برای این پایگاه داده ساده بوده و زبان آن نیز بر پایه جاوا اسکریپت میباشد که برای اکثر برنامهنویسان قابل درک است.
تاکنون توسط شرکتهای مختلف پیادهسازیهای مختلفی از این سیستم انجام شده است که از مهمترین و پر استفادهترین آنها میتوان به موارد زیر اشاره کرد:
جلوگیری از ارسال Spam در ASP.NET MVC
- این برنامهها، user agentهای متفاوتی را به ازای هر درخواست ارسال میکنند (عموما). بنابراین مورد دوم هم علاوه بر مورد سوم نباید بکار گرفته شود.
- دو نوع هش در حالت کلی وجود دارند. هشهای سریع و هشهای امن. هشهای امن سعی میکنند این تضمین را ارائه دهند که به ازای یک ورودی مشخص، خروجی منحصربفردی را تولید کنند؛ اما ... با قیمت کندتر بودن عملیات هش. هشهای سریع، مانند xxHash، برای یک چنین مواردی که نیاز هست کلید کش تولید شود بکار گرفته میشوند. الزاما مانند هشهای امن سعی در تولید خروجیهای منحصربفردی نمیکنند، اما تا این اندازه دقیق هستند که در بانکهای اطلاعاتی key-value store فوق سریعی مانند Redis از آنها استفاده میشود. بنابراین در یک چنین مواردی مانند سناریوی جاری بهتر است از هشهای سریع استفاده شود. البته اگر آدرس صفحه و همچنین UA را حذف کنیم، نیازی به هش کردن نخواهد بود؛ چون IP را میتوان بعنوان کلید درنظر گرفت.
- بررسی UA از دیدگاه دیگری به صورت جداگانه میتواند مفید باشد. تشخیص باتهای شناخته شده و بستن دسترسی آنها.
EF Code First #7
به نظر من کار درستی انجام دادن. زمانیکه نیاز به بهروز رسانی primary key دارید یعنی طراحی بانک اطلاعاتی شما یا نرمال نیست یا مشکل داره.
البته میتونید رویه ذخیره شده درست کنید برای اینکارها و دستی مسایل رو به زور اعمال کنید ولی به صورت پیش فرض خارج از سیستم Tracking آن که به صورت خودکار اطلاعات اشیاء مرتبط را به روز میکند، Cascade Update دیگری وجود ندارد.