نرم افزارهای Windows 7, Windows Server 2008 R2 and SQL Server 2008 SP2 32 & 64 bit Enterprise Edition موفق به کسب گواهینامه امنیتی Common Criteria شدند. کسب این مجوز امنیتی یکی از شروط اصلی و اجباری استفاده از یک نرم افزار در وزارت دفاع آمریکا است.
این بررسیها زیر نظر وزارت دفاع و آژانس امنیت ملی آمریکا و همچنین آلمان برگزار شده و گزارشهای مرتبط با ویندوز 7 و SQL Server 2008 را از اینجا میتوانید دریافت کنید: (+) و (+)
ماخذ: (+)
مطالب مشابه:
امنیت SQL Server 2008
مقایسه امنیتی نگارشهای مختلف ویندوز
نصب قالب پروژه از طریق نیوگت
dotnet new --install DNTFrameworkCoreTemplateAPI::*
dotnet new dntcore-api
بررسی قسمتهای مختلف قالب پروژه
2- پروژه Infrastructure دربرگیرنده DbContext، مهاجرتها و کلاسهای تنظیمات نگاشت موجودیتها به جداول بانک اطلاعاتی پروژه میباشد. به عنوان مثال، به صورت پیشفرض تنظیمات نگاشت موجودیتهای کاربر و گروهکاربری و موجودیتهای وابسته آنها در این قالب پیادهسازی شدهاند. همچنین دو مهاجرت CreateInitialSchema و CreateIdentitySchema ایجاده شدهاند.
3- پروژه Application دربرگیرنده مدلها/DTOها، اعتبارسنجهای مدلها، سرویسها و همچنین Eventهای سفارشی و Handlerهای رویدادهای متناظر با موجودیتهای سیستم، میباشد. همانطور که شکل زیر ملاحظه میکنید، برای موجودیتهای کاربر و گروهکاربری طراحی و پیادهسازی پیشفرضی از قسمتهای مذکور ارائه شده است.
5- از پروژه Common نیز میتوان به عنوان دربرگیرنده کلاسهای کمکی مورد استفاده در سایر قسمتها، بهره برد.
6- پروژه UnitTests دربرگیرده آزمونهای واحد پروژه میباشد. به عنوان مثال، به صورت پیشفرض آزمونهای واحد مرتبط با UserValidator و RoleValidator به صورت کامل در این قالب تدارک دیده شده است.
7- پروژه IntegrationTests دربرگیرنده آزمونهای جامعیت مرتبط با پروژه میباشد. به عنوان مثال، آزمونهای جامعیت متناظر با سرویسهای کاربر و گروهکاربری نیز در این قالب تدارک دیده شده است.
نکته: بدلیل اینکه مکانیزم اعتبارسنجی خودکار ورودیها به عنوان یک Aspect برروی این سرویسها اعمال شده است و بدین ترتیب در فرآیند تست سرویسها نیز دخالت دارند، به صورت ناخواسته به سمت آزمون جامعیت سوق پیدا کردهایم. با این حال اگر برای لایه بالاتر/خارجی پروژه خود یا همان API در قالب، قصد تهیه آزمون جامعیت داشته باشید، میتوانید این تنظیمات ValidationInterceptor را از فایل ApplicationRegistry در پروژه Application حذف کرده و آزمونهای سرویسها را در قالب آزمون واحد انجام دهید. با این حال باید توجه کنید که برای برخی از سناریوها که امکانات هیچ کدام از مهیاکنندههای InMemory و SQLite درون حافظه، جوابگوی نیاز شما نباشد، نیاز خواهید داشت تا از بانک اطلاعاتی واقعی از جمله LocalDb استفاده کنید؛ در این صورت آزمونهای شما نیز در ردیف آزمونهای جامعیت قرار خواهند داشت.
8- پروژه API دربرگیرنده کنترلرها، هابهای SignalR، زیرساخت Authentication مبتنیبر JWT و سایر تنظیمات آغازین پروژه، میباشد. CRUD API متناظر با موجودیتهای کاربر و گروهکاربری نیز در این قالب تدارک دیده شده است.
کدهای کامل این قسمت را میتوانید از اینجا دریافت کنید.
کامپوننتی را با نام SynchronousInitComponent با کد زیر درنظر میگیریم. همانطور که از اسم آن مشخص است این کامپوننت به صورت متقارن یا همزمان پیادهسازی شده است:
<p>Sync rendered by thread @IdOfRenderingThread</p> @code { int IdOfRenderingThread; protected override void OnInitialized() { base.OnInitialized(); IdOfRenderingThread = System.Threading.Thread.CurrentThread.ManagedThreadId; } }
حال در کامپوننت دیگری برای مثال کامپوننت index، کامپوننت همزمان فوق را به شکل زیر فراخوانی میکنیم:
@page "/" <h1>Components with synchronous OnInitialized()</h1> @for (int i = 0; i < 5; i++) { <SynchronousInitComponent /> }
Components with synchronous OnInitialized() Sync rendered by thread 4 Sync rendered by thread 4 Sync rendered by thread 4 Sync rendered by thread 4 Sync rendered by thread 4
حال همین آزمایش را با متدهای نامتقارن یا ناهمزمان انجام میدهیم. کامپوننت AsynchronousInitComponent را با کد زیر درنظر بگیرید:
<p>Async rendered by thread @IdOfRenderingThread</p> @code { int IdOfRenderingThread; protected override async Task OnInitializedAsync() { // Runs synchronously as there is no code in base.OnInitialized(), // so the same thread is used await base.OnInitializedAsync().ConfigureAwait(false); IdOfRenderingThread = System.Threading.Thread.CurrentThread.ManagedThreadId; // Awaiting will schedule a job for later, and we will be assigned // whichever worker thread is next available await Task.Delay(1000).ConfigureAwait(false); IdOfRenderingThread = System.Threading.Thread.CurrentThread.ManagedThreadId; } }
@page "/async-init" <h1>Components with asynchronous OnInitializedAsync()</h1> @for (int i = 0; i < 5; i++) { <AsynchronousInitComponent/> }
Components with asynchronous OnInitializedAsync() Async rendered by thread 4 Async rendered by thread 4 Async rendered by thread 4 Async rendered by thread 4 Async rendered by thread 4
Components with asynchronous OnInitializedAsync() Async rendered by thread 7 Async rendered by thread 18 Async rendered by thread 10 Async rendered by thread 13 Async rendered by thread 11
تکنولوژی CTE از نسخه SQL Server 2005 رسمیت یافته است و شامل یک result set موقتی[1] است که دارای نام مشخص بوده و میتوان از آن در دستورات SELECT, INSERT, UPDATE, DELETEاستفاده کرد. همچنین از CTE میتوان در دستور CREATE VIEW و دستور SELECT مربوط به آن استفاده کرد. در نسخه SQL Server 2008 نیز امکان استفاده از CTE در دستور MERGE فراهم شده است.
در SQL Serverاز دو نوع CTE بازگشتی[2] و غیر بازگشتی[3] پشتیبانی میشود. در این مقاله سعی شده است نحوه تعریف و استفاده از هر دو نوع آن آموزش داده شود.
انواع روشهای ایجاد جداول موقت
برای استفاده از جداول موقتی در سرور اسکیوال، سه راه زیر وجود دارد.
روش اول: استفاده از دستوری مانند زیر است که سبب ایجاد جدول موقتی در بانک سیستمی tempdb میشود. زمانیکه شما ارتباط خود را با سرور SQL قطع میکنید به صورت اتوماتیک جداول موقت شما از بانک tempdb حذف میشوند. این روش در برنامه نویسی پیشنهاد نمیشود و فقط در کارهای موقتی و آزمایشی مناسب است.
SELECT * INTO #temptable FROM [Northwind].[dbo].[Products] UPDATE #temptable SET [UnitPrice] = [UnitPrice] + 10
روش دوم: استفاده از متغیر نوع Table است، که نمونه آن در مثال زیر دیده میشود. زمانیکه از محدوده[4] جاری کد[5] خودتان خارج شوید آن متغیر نیز از حافظه پاک میشود. از این روش، عموما در کدهای Stored Procedureها و UserDefined Functionها استفاده میشود.
DECLARE @tempTable TABLE ( [ProductID] [int] NOT NULL, [ProductName] [nvarchar](40) NOT NULL, [UnitPrice] [money] NULL ) INSERT INTO @tempTable SELECT [ProductID], [ProductName], [UnitPrice] FROM [Northwind].[dbo].[Products] UPDATE @temptable SET [UnitPrice] = [UnitPrice] + 10
روش سوم: استفاده از CTE است که مزیتهایی نسبت به دو روش قبلی دارد و در بخش بعدی به نحوه تعریف و استفاده از آن خواهیم پرداخت.
کار با CTE
ساده ترین شکل تعریف یک CTE به صورت زیر است:
WITH yourName [(Column1, Column2, ...)] AS ( your query )
your query شامل دستوری است که سبب تولید یک result set میشود. قواعد تعریف این کوئری مشابه قواعد تعریف کوئری است که در دستور CREATE VIEW کاربرد دارد.
همانطور که از این تصویر مشخص است میتوان چندین بلوک از این ساختار را به دنبال هم تعریف نمود که با کاما از هم جدا میشوند. در واقع یکی از کاربردهای CTE ایجاد قطعات کوچکی است که امکان استفاده مجدد را به شما داده و میتواند سبب خواناتر شدن کدهای پیچیده شود.
یکی دیگر از کاربردهای CTE آنجایی است که شما نمیخواهید یک شی Viewی عمومی تعریف کنید و در عین حال میخواهید از مزایای Viewها بهرمند شوید.
و همچنین از کاربردهای دیگر CTE تعریف جدول موقت و استفاده از آن جدول به صورت همزمان در یک دستور است.
بعد از آنکه CTE یا CTEهای خودتان را تعریف کردید آنگاه میتوانید مانند جداول معمولی از آنها استفاده کنید. استفاده از این جداول توسط دستوری خواهد بود که دقیقا بعد از تعریف CTE نوشته میشود.
ایجاد یک CTE غیر بازگشتی[6]
مثال اول، یک CTE غیر بازگشتی ساده را نشان میدهد.
WITH temp AS ( SELECT [ProductName], [UnitPrice] FROM [Northwind].[dbo].[Products] ) SELECT * FROM temp ORDER BY [UnitPrice] DESC
مثال دوم نمونهای دیگر از یک CTE غیر بازگشتی است.
WITH orderSales (OrderID, Total) AS ( SELECT [OrderID], SUM([UnitPrice]*[Quantity]) AS Total FROM [Northwind].[dbo].[Order Details] GROUP BY [OrderID] ) SELECT O.[ShipCountry], SUM(OS.[Total]) AS TotalSales FROM [Northwind].[dbo].[Orders] AS O INNER JOIN [orderSales] AS OS ON O.[OrderID] = OS.[OrderID] GROUP BY O.[ShipCountry] ORDER BY TotalSales DESC
مثال سوم استفاده از دو CTE را به صورت همزمان نشان میدهد:
WITH customerList AS ( SELECT [CustomerID], [ContactName] FROM [Northwind].[dbo].[Customers] WHERE [Country] ='UK' ) ,orderList AS ( SELECT [CustomerID], [OrderDate] FROM [Northwind].[dbo].[Orders] WHERE YEAR([OrderDate])< 2000 ) SELECT cl.[ContactName], YEAR(ol.[OrderDate]) AS SalesYear FROM customerList AS cl JOIN orderList AS ol ON cl.[CustomerID] = ol.[CustomerID]
مثال چهارم استفاده مجدد از یک CTE را نشان میدهد. فرض کنید جدولی به نام digits داریم که فقط یک فیلد digit دارد و دارای 10 رکورد با مقادیر 0 تا 9 است. مانند تصویر زیر
حال میخواهیم از طریق CROSS JOIN اعداد 1 تا 100 را با استفاده از مقادیر این جدول تولید کنیم. کد زیر آنرا نشان میدهد:
WITH digitList AS ( SELECT [digit] from [digits] ) SELECT a.[digit] * 10 + b.[digit] + 1 AS [Digit] FROM [digitList] AS a CROSSJOIN [digitList] AS b
حتی میتوان از یک CTE در کوئری CTE بعدی مانند کد زیر استفاده کرد.
WITH CTE_1 AS ( .... ), CTE_2 AS ( SELECT ... FROM CTE_1 JOIN ... ) SELECT * FROM FOO LEFTJOIN CTE_1 LEFTJOIN CTE_2
ایجاد یک CTE بازگشتی[7]
از CTE بازگشتی برای پیمایش جداولی استفاده میشود که رکوردهای آن دارای رابطه سلسله مراتبی یا درختی است. نمونه این جداول، جدول کارمندان است که مدیر هر کارمند نیز مشخص شده است یا جدولی که ساختار سازمانی را نشان میدهد یا جدولی که موضوعات درختی را در خود ذخیره کرده است. یکی از مزایای استفاده از CTE بازگشتی، سرعت کار آن در مقایسه با روشهای پردازشی دیگر است.
ساختار کلی یک دستور CTE بازگشتی به صورت زیر است.
WITH cteName AS ( query1 UNION ALL query2 )
UNION
UNION ALL
INTERSECT
EXCEPT
query1 شامل دستوری است که اولین سری از رکوردهای result set نهایی را تولید میکند. اصطلاحا به این کوئری anchor memberمیگویند.
بعد از دستور query1، حتما بایستی از UNION ALL و امثال آنها استفاده شود.
سپس query2 ذکر میشود. اصطلاحا به این کوئری recursive member گفته میشود. این کوئری شامل دستوری است که سطوح بعدی درخت را تولید خواهد کرد. این کوئری دارای شرایط زیر است.
- حتما بایستی به CTE که همان cteName است اشاره کرده و در جایی از آن استفاده شده باشد. به عبارت دیگر از رکوردهای موجود در جدول موقت استفاده کند تا بتواند رکوردهای بعدی را تشخیص دهد.
- حتما بایستی مطمئن شوید که شرایط کافی برای پایان حلقه پیمایش رکوردها را داشته باشد در غیر این صورت سبب تولید حلقه بی پایان[9] خواهد شد.
بدنه CTE میتواند حاوی چندین anchor member و چندین recursive member باشد ولی فقط recursive memberها هستند که به CTE اشاره میکنند.
برای آنکه نکات فوق روشن شود به مثالهای زیر توجه کنید.
فرض کنید جدولی از کارمندان و مدیران آنها داریم که به صورت زیر تعریف و مقداردهی اولیه شده است.
IFOBJECT_ID('Employees','U')ISNOTNULL DROPTABLE dbo.Employees GO CREATETABLE dbo.Employees ( EmployeeID intNOTNULLPRIMARYKEY, FirstName varchar(50)NOTNULL, LastName varchar(50)NOTNULL, ManagerID intNULL ) GO INSERTINTO Employees VALUES (101,'Alireza','Nematollahi',NULL) INSERTINTO Employees VALUES (102,'Ahmad','Mofarrahzadeh', 101) INSERTINTO Employees VALUES (103,'Mohammad','BozorgGhommi', 102) INSERTINTO Employees VALUES (104,'Masoud','Narimani', 103) INSERTINTO Employees VALUES (105,'Mohsen','Hashemi', 103) INSERTINTO Employees VALUES (106,'Aref','Partovi', 102) INSERTINTO Employees VALUES (107,'Hosain','Mahmoudi', 106) INSERTINTO Employees VALUES (108,'Naser','Pourali', 106) INSERTINTO Employees VALUES (109,'Reza','Bagheri', 102) INSERTINTO Employees VALUES (110,'Abbas','Najafian', 102)
مثال اول: میخواهیم فهرست کارمندان را به همراه نام مدیر آنها و شماره سطح درخت نمایش دهیم. کوئری زیر نمونهای از یک کوئری بر اساس CTE بازگشتی میباشد.
WITHcteReports(EmpID, FirstName, LastName, MgrID, EmpLevel) AS ( SELECT EmployeeID, FirstName, LastName, ManagerID, 1 FROM Employees WHERE ManagerID ISNULL UNIONALL SELECT e.EmployeeID, e.FirstName, e.LastName, e.ManagerID,r.EmpLevel + 1 FROM Employees e INNERJOINcteReports r ON e.ManagerID = r.EmpID ) SELECT FirstName +' '+ LastName AS FullName, EmpLevel, (SELECT FirstName +' '+ LastName FROM Employees WHERE EmployeeID = cteReports.MgrID)AS Manager FROMcteReports ORDERBY EmpLevel, MgrID
کوئری دوم در بدنه CTE از یک JOIN بین Employees و cteReports استفاده کرده و کارمندان زیر دست هر کارمند قبلی (فرزندان) را بدست آورده و مقدار شماره سطح آنرا به صورت Level+1 تنظیم میکند.
در نهایت با استفاده از CTE و یک subquery جهت بدست آوردن نام مدیر هر کارمند، نتیجه نهایی تولید میشود.
مثال دوم: میخواهیم شناسه یک کارمند را بدهیم و نام او و نام مدیران وی را به عنوان جواب در خروجی بگیریم.
WITHcteReports(EmpID, FirstName, LastName, MgrID, EmpLevel) AS ( SELECT EmployeeID, FirstName, LastName, ManagerID, 1 FROM Employees WHERE EmployeeID = 110 UNIONALL SELECTe.EmployeeID, e.FirstName, e.LastName, e.ManagerID,r.EmpLevel + 1 FROM Employees e INNERJOINcteReports r ON e.EmployeeID = r.MgrID ) SELECT FirstName +' '+ LastName AS FullName, EmpLevel FROMcteReports ORDERBY EmpLevel
دومین تفاوت اصلی این کوئری با مثال قبلی، در قسمت دوم دیده میشود. شما میخواهید مدیر (پدر) کارمندی که در آخرین پردازش در جدول موقت قرار گرفته است را استخراج کنید.
[1] a temporary named result set
[2] recursive
[3] nonrecursive
[4] Scope
[5]مثلا محدوده کدهای یک روال یا یک تابع
[6] nonrecursive
[7] recursive
[8] member
[9] Infinite loop