مطالب
الگوی استخر اشیاء Object Pool Pattern
الگوی استخر اشیاء، جزو الگوهای تکوینی است و کار آن جلوگیری از ایجاد اشیاء تکراری و محافظت از به هدر رفتن حافظه است. نحوه کار این الگو بدین شکل است که وقتی کاربر درخواست نمونه‌ای از یک شیء را می‌دهد، بعد از اتمام کار، شیء نابود نمی‌شود؛ بلکه به استخر بازگشت داده می‌شود تا در درخواست‌های آینده، مجددا مورد استفاده قرار گیرد. این کار موجب عدم هدر رفتن حافظه و همچنین بالا رفتن کارآیی برنامه می‌گردد. این الگو به خصوص برای اشیایی که مدت کوتاهی مورد استفاده قرار میگیرند و آماده سازی آن‌ها هزینه بر است بسیار کارآمد می‌باشد. از آنجا که هزینه‌ی ساخت و نابود سازی در حد بالایی قرار دارد و آن شیء به طور مکرر مورد استفاده قرار می‌گیرد، زمان زیادی صرفه جویی می‌شود.

در این الگو ابتدا شیء از استخر درخواست می‌شود. اگر قبلا ایجاد شده باشد، مجددا مورد استفاده قرار می‌گیرد. در غیر این صورت نمونه جدیدی ایجاد می‌شود و وقتی که کار آن پایان یافت به استخر بازگشت داده شده و نگهداری می‌شود، تا زمانی که مجددا درخواست استفاده از آن برسد.
 یکی از نکات مهم و کلیدی این است که وقتی کار شیء مربوطه تمام شد، باید اطلاعات شیء قبلی و داده‌های آن نیز پاکسازی شوند؛ در غیر این صورت احتمال آسیب و خطا در برنامه بالا می‌رود و این الگو را به یک ضد الگو تبدیل خواهد کرد.
نمونه‌ای از پیاده سازی این الگو را در دات نت، می‌توانید در data provider‌های مخصوص SQL Server نیز ببینید. از آنجا که ایجاد اتصال به دیتابیس، هزینه بر بوده و دستورات در کوتاه‌ترین زمان ممکن اجرا می‌شوند، این کانکشن‌ها یا اتصالات بعد از بسته شدن از بین نمی‌روند، بلکه در استخر مانده تا زمانیکه مجددا نمونه مشابهی از آن‌ها درخواست شود تا دوباره مورد استفاده قرار بگیرند تا از هزینه اولیه برای ایجاد آن‌ها پرهیز شود. استفاده از این الگو در برنامه نویسی با سوکت ها، تردها و کار با اشیاء گرافیکی بزرگ مثل فونت‌ها و تصاویر Bitmap کمک شایانی می‌کند. ولی در عوض برای اشیای ساده می‌تواند کارآیی را به شدت کاهش دهد.

الگوی بالا را در سی شارپ بررسی می‌کنیم:
ابتدا کلاس PooledObject را به عنوان یک شیء بزرگ و پر استفاده ایجاد می‌کنیم:
 public class PooledObject
    {
        DateTime _createdAt = DateTime.Now;

        public DateTime CreatedAt
        {
            get { return _createdAt; }
        }

        public string TempData { get; set; }

        public void DoSomething(string name)
        {
            Console.WriteLine($"{name} : {TempData} is written on {CreatedAt}");
        }
    }
tempdata ویژگی است که باید برای هر شیء، مجزا باشد. پس باید دقت داشت برای استفاده‌های بعدی نیاز است پاک سازی شود.
بعد از آن کلاس پول را پیاده سازی می‌کنیم:
public static class Pool
{
    private static List<PooledObject> _available = new List<PooledObject>();
    private static List<PooledObject> _inUse = new List<PooledObject>();
 
    public static PooledObject GetObject()
    {
        lock(_available)
        {
            if (_available.Count != 0)
            {
                PooledObject po = _available[0];
                _inUse.Add(po);
                _available.RemoveAt(0);
                return po;
            }
            else
            {
                PooledObject po = new PooledObject();
                _inUse.Add(po);
                return po;
            }
        }
    }
 
    public static void ReleaseObject(PooledObject po)
    {
        CleanUp(po);
 
        lock (_available)
        {
            _available.Add(po);
            _inUse.Remove(po);
        }
    }
 
    private static void CleanUp(PooledObject po)
    {
        po.TempData = null;
    }
}
در کلاس بالا، کاربر با متد GetObject، درخواست شی‌ءایی را می‌کند و متد نگاه می‌کند که اگر لیست موجودی، پر باشد، اولین نمونه‌ی در دسترس را ارسال می‌کند. ولی در صورتیکه نمونه‌ای از آن نباشد، یک نمونه‌ی جدید را ایجاد کرده و آن را در لیست مورد استفاده‌ها قرار می‌دهد و به کاربر باز می‌گرداند.
متد Release Object وظیفه‌ی بازگرداندن شیء را به استخر، دارد که از لیست در حال استفاده‌ها آن را حذف کرده و به لیست موجودی اضافه می‌کند. متد Cleanup در این بین وظیفه ریست کردن شیء را دارد تا مشکلی که در بالا بیان کردیم رخ ندهد.
کد زیر را اجرا می‌کنیم:
            var obj1 = Pool.GetObject();
            obj1.DoSomething("obj1");

            Thread.Sleep(2000);
            var obj2 = Pool.GetObject();
            obj2.DoSomething("obj2");
            Pool.ReleaseObject(obj1);

            Thread.Sleep(2000);
            var obj3 = Pool.GetObject();
            obj3.DoSomething("obj3");
نتیجه به شکل زیر است:
obj1 :  is written on 4/21/2016 11:25:26 AM
obj2 :  is written on 4/21/2016 11:25:28 AM
obj3 :  is written on 4/21/2016 11:25:26 AM
ابتدا شیء obj1 ایجاد می‌شود و سپس obj2 و بعد از آن obj1 به لیست موجودی‌ها بازگشته و برای obj3 همان شیء را بازگشت می‌هد که برای obj1 ساخته بود. توقف تردها در این مثال برای مشاهده‌ی بهتر زمان است.
مطالب
مثال‌هایی در مورد استفاده از SQL Server 2005 Reporting Services
SQL Server 2005 Reporting Services راه حلی مبتنی بر سرور جهت گزارشگیری‌های جامع با قابلیت ارائه گزارش‌های paper-based ، ad hoc و Web-based است. (جهت آشنایی بیشتر می‌توان به مقاله "SQL Server Reporting Service چیست؟" آقای رمضانی مراجعه کرد)

اخیرا مجموعه‌ای مثال در مورد کار با Reporting Services ارائه شده است که از آدرس زیر قابل دریافت است:

این مجموعه شامل 7 بسته آموزشی و مثال‌های مرتبط می‌باشد:

SQL Server 2005 Integration Services Log Reports
SQL Server 2005 Report Pack for Microsoft Dynamics Axapta 3.0
SQL Server 2005 Report Pack for Microsoft Dynamics Navision 4.0
SQL Server 2005 Report Pack for Microsoft Dynamics Great Plains 8.0
SQL Server 2005 Report Pack for Microsoft Dynamics Great Plains 9.0
SQL Server 2005 Report Pack for Microsoft Internet Information Services (IIS)
SQL Server 2005 Report Pack for Financial Reporting


نظرات مطالب
انجام کارهای زمانبندی شده در برنامه‌های ASP.NET توسط DNT Scheduler
- به اندازه کافی در نظرات این بحث در مورد زنده نگه داشتن یک برنامه ASP.NET بحث شده. کمی وقت بگذارید و آن‌ها را مطالعه کنید.
+ اگر برنامه مالی است، احتمالا دسترسی کاملی به سرور و همچنین SQL Server (اگر با آن کار می‌کنید) دارید. در این حالت برای به روز رسانی زمانبندی شده‌ی چند رکورد شاید بهتر باشد از سرویس معروف و همیشه در حال اجرای SQL Server agent استفاده کنید. در اینجا نیز می‌شود یک job را که متشکل از دستورات T-SQL است، در فواصل زمانی مشخصی اجرا کرد.
مطالب
EF Code First #15

EF Code first و بانک‌های اطلاعاتی متفاوت

در آخرین قسمت از سری EF Code first بد نیست نحوه استفاده از بانک‌های اطلاعاتی دیگری را بجز SQL Server نیز بررسی کنیم. در اینجا کلاس‌های مدل و کدهای مورد استفاده نیز همانند قسمت 14 است و تنها به ذکر تفاوت‌ها و نکات مرتبط اکتفاء خواهد شد.


حالت کلی پشتیبانی از بانک‌های اطلاعاتی مختلف توسط EF Code first

EF Code first با کلیه پروایدرهای تهیه شده برای ADO.NET 3.5 که پشتیبانی از EF را لحاظ کرده باشند،‌ به خوبی کار می‌کند. پروایدرهای مخصوص ADO.NET 4.0، تنها سه گزینه DeleteDatabase/CreateDatabase/DatabaseExists را نسبت به نگارش قبلی بیشتر دارند و EF Code first ویژگی‌های بیشتری را طلب نمی‌کند.
بنابراین اگر حین استفاده از پروایدر ADO.NET مخصوص بانک اطلاعاتی خاصی با پیغام «CreateDatabase is not supported by the provider» مواجه شدید، به این معنا است که این پروایدر برای دات نت 4 به روز نشده است. اما به این معنا نیست که با EF Code first کار نمی‌کند. فقط باید یک دیتابیس خالی از پیش تهیه شده را به برنامه معرفی کنید تا مباحث Database Migrations به خوبی کار کنند؛ یا اینکه کلا می‌توانید Database Migrations را خاموش کرده (متد Database.SetInitializer را با پارامتر نال فراخوانی کنید) و فیلدها و جداول را دستی ایجاد کنید.


استفاده از EF Code first با SQLite

برای استفاده از SQLite در دات نت ابتدا نیاز به پروایدر ADO.NET آن است: «مکان دریافت درایور‌های جدید SQLite مخصوص دات نت»
ضمن اینکه به نکته «استفاده از اسمبلی‌های دات نت 2 در یک پروژه دات نت 4» نیز باید دقت داشت.
و یکی از بهترین management studio هایی که برای آن تهیه شده: «SQLite Manager»
پس از دریافت پروایدر آن، ارجاعی را به اسمبلی System.Data.SQLite.dll به برنامه اضافه کنید.
سپس فایل کانفیگ برنامه را به نحو زیر تغییر دهید:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=4.3.1.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</configSections>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0"/>
</startup>

<connectionStrings>
<clear/>
<add name="Sample09Context"
connectionString="Data Source=CodeFirst.db"
providerName="System.Data.SQLite"/>
</connectionStrings>
</configuration>

همانطور که ملاحظه می‌کنید، تفاوت آن با قبل، تغییر connectionString و providerName است.
اکنون اگر همان برنامه قسمت قبل را اجرا کنیم به خطای زیر برخواهیم خورد:
«The given key was not present in the dictionary»
در این مورد هم توضیح داده شد. سه گزینه DeleteDatabase/CreateDatabase/DatabaseExists در پروایدر جاری SQLite برای دات نت وجود ندارد. به همین جهت نیاز است فایل «CodeFirst.db» ذکر شده در کانکشن استرینگ را ابتدا دستی درست کرد.
برای مثال از افزونه SQLite Manager استفاده کنید. ابتدا یک بانک اطلاعاتی خالی را درست کرده و سپس دستورات زیر را بر روی بانک اطلاعاتی اجرا کنید تا دو جدول خالی را ایجاد کند (در برگه Execute sql افزونه SQLite Manager):

CREATE TABLE [Payees](
[Id] [integer] PRIMARY KEY AUTOINCREMENT NOT NULL,
[Name] [text] NULL,
[CreatedOn] [datetime] NOT NULL,
[CreatedBy] [text] NULL,
[ModifiedOn] [datetime] NOT NULL,
[ModifiedBy] [text] NULL
);

CREATE TABLE [Bills](
[Id] [integer] PRIMARY KEY AUTOINCREMENT NOT NULL,
[Amount] [float](18, 2) NOT NULL,
[Description] [text] NULL,
[CreatedOn] [datetime] NOT NULL,
[CreatedBy] [text] NULL,
[ModifiedOn] [datetime] NOT NULL,
[ModifiedBy] [text] NULL,
[Payee_Id] [integer] NULL
);

سپس سطر زیر را نیز به ابتدای برنامه اضافه کنید:

Database.SetInitializer<Sample09Context>(null);

به این ترتیب database migrations خاموش می‌شود و اکنون برنامه بدون مشکل کار خواهد کرد.
فقط باید به یک سری نکات مانند نوع داده‌ها در بانک‌های اطلاعاتی مختلف دقت داشت. برای مثال integer در اینجا از نوع Int64 است؛ بنابراین در برنامه نیز باید به همین ترتیب تعریف شود تا نگاشت‌ها به درستی انجام شوند.

در کل تنها مشکل پروایدر فعلی SQLite عدم پشتیبانی از مباحث database migrations است. این مورد را خاموش کرده و تغییرات ساختار بانک اطلاعاتی را به صورت دستی به بانک اطلاعاتی اعمال کنید. بدون مشکل کار خواهد کرد.

البته اگر به دنبال پروایدری تجاری با پشتیبانی از آخرین نگارش EF Code first هستید، گزینه زیر نیز مهیا است:
http://devart.com/dotconnect/sqlite/
برای مثال اگر علاقمند به استفاده از حالت تشکیل بانک اطلاعاتی SQLite در حافظه هستید (با رشته اتصالی ویژه Data Source=:memory:;Version=3;New=True;)،‌ فعلا تنها گزینه مهیا استفاده از پروایدر تجاری فوق است؛ زیرا مبحث Database Migrations را به خوبی پشتیبانی می‌کند.



استفاده از EF Code first با SQL Server CE

قبلا در مورد «استفاده از SQL-CE به کمک NHibernate» مطلبی را در این سایت مطالعه کرده‌اید. سه مورد اول آن با EF Code first یکی است و تفاوتی نمی‌کند (یک سری بحث عمومی مشترک است). البته با یک تفاوت؛ در اینجا EF Code first قادر است یک بانک اطلاعاتی خالی SQL Server CE را به صورت خودکار ایجاد کند و نیازی نیست تا آن‌را دستی ایجاد کرد. مباحث database migrations و به روز رسانی خودکار ساختار بانک اطلاعاتی نیز در اینجا پشتیبانی می‌شود.
برای استفاده از آن ابتدا ارجاعی را به اسمبلی System.Data.SqlServerCe.dll قرار گرفته در مسیر Program Files\Microsoft SQL Server Compact Edition\v4.0\Desktop اضافه کنید.
سپس رشته اتصالی به بانک اطلاعاتی و providerName را به نحو زیر تغییر دهید:

<connectionStrings>
<clear/>
<add name="Sample09Context"
connectionString="Data Source=mydb.sdf;Password=1234;Encrypt Database=True"
providerName="System.Data.SqlServerCE.4.0"/>
</connectionStrings>


بدون نیاز به هیچگونه تغییری در کدهای برنامه، همین مقدار تغییر در تنظیمات ابتدایی برنامه برای کار با SQL Server CE کافی است.
ضمنا مشکلی هم با فیلد Identity در آخرین نگارش EF Code first وجود ندارد؛ برخلاف حالت database first آن که پیشتر این اجازه را نمی‌داد و خطای «Server-generated keys and server-generated values are not supported by SQL Server Compact» را ظاهر می‌کرد.



استفاده از EF Code first با MySQL

برای استفاده از EF Code first با MySQL (نگارش 5 به بعد البته) ابتدا نیاز است پروایدر مخصوص ADO.NET آن‌را دریافت کرد: (^)
که از EF نیز پشتیبانی می‌کند. پس از نصب آن، ارجاعی را به اسمبلی MySql.Data.dll قرار گرفته در مسیر Program Files\MySQL\MySQL Connector Net 6.5.4\Assemblies\v4.0 به پروژه اضافه نمائید.
سپس رشته اتصالی و providerName را به نحو زیر تغییر دهید:

<connectionStrings>
<clear/>
<add name="Sample09Context"
connectionString="Datasource=localhost; Database=testdb2; Uid=root; Pwd=123;"
providerName="MySql.Data.MySqlClient"/>
</connectionStrings>

<system.data>
<DbProviderFactories>
<remove invariant="MySql.Data.MySqlClient"/>
<add name="MySQL Data Provider"
invariant="MySql.Data.MySqlClient"
description=".Net Framework Data Provider for MySQL"
type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.5.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
</DbProviderFactories>
</system.data>

همانطور که مشاهده می‌کنید در اینجا شماره نگارش دقیق پروایدر مورد استفاده نیز ذکر شده است. برای مثال اگر چندین پروایدر روی سیستم نصب است، با مقدار دهی DbProviderFactories می‌توان از نگارش مخصوصی استفاده کرد.

با این تغییرات پس از اجرای برنامه قسمت قبل، به خطای زیر برخواهیم خورد:
The given key was not present in the dictionary

توضیحات این مورد با قسمت SQLite یکی است؛ به عبارتی نیاز است بانک اطلاعاتی testdb را دستی درست کرد. همچنین جداول و فیلدها را نیز باید دستی ایجاد کرد و database migrations را نیز باید خاموش کرد (پارامتر Database.SetInitializer را به نال مقدار دهی کنید).
برای این منظور یک دیتابیس خالی را ایجاد کرده و سپس دو جدول زیر را به آن اضافه کنید:

CREATE TABLE IF NOT EXISTS `bills` (
`Id` int(11) NOT NULL AUTO_INCREMENT,
`Amount` float DEFAULT NULL,
`Description` varchar(400) CHARACTER SET utf8 COLLATE utf8_persian_ci NOT NULL,
`CreatedOn` datetime NOT NULL,
`CreatedBy` varchar(400) CHARACTER SET utf8 COLLATE utf8_persian_ci NOT NULL,
`ModifiedOn` datetime NOT NULL,
`ModifiedBy` varchar(400) CHARACTER SET utf8 COLLATE utf8_persian_ci NOT NULL,
`Payee_Id` int(11) NOT NULL,
PRIMARY KEY (`Id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_persian_ci AUTO_INCREMENT=1 ;

CREATE TABLE IF NOT EXISTS `payees` (
`Id` int(11) NOT NULL AUTO_INCREMENT,
`Name` varchar(400) CHARACTER SET utf8 COLLATE utf8_persian_ci NOT NULL,
`CreatedOn` datetime NOT NULL,
`CreatedBy` varchar(400) CHARACTER SET utf8 COLLATE utf8_persian_ci NOT NULL,
`ModifiedOn` datetime NOT NULL,
`ModifiedBy` varchar(400) CHARACTER SET utf8 COLLATE utf8_persian_ci NOT NULL,
PRIMARY KEY (`Id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_persian_ci AUTO_INCREMENT=1 ;

پس از این تغییرات، برنامه بدون مشکل اجرا خواهد شد (ایجاد بانک اطلاعاتی خالی به همراه ایجاد ساختار جداول و خاموش کردن database migrations که توسط این پروایدر پشتیبانی نمی‌شود).

به علاوه پروایدر تجاری دیگری هم در سایت devart.com برای MySQL و EF Code first مهیا است که مباحث database migrations را به خوبی مدیریت می‌کند.


مشکل!
اگر به همین نحو برنامه را اجرا کنیم، فیلدهای یونیکد فارسی ثبت شده در MySQL با «??????? ?? ????» مقدار دهی خواهند شد و تنظیم CHARACTER SET utf8 COLLATE utf8_persian_ci نیز کافی نبوده است (این مورد با SQLite یا نگارش‌های مختلف SQL Server بدون مشکل کار می‌کند و نیاز به تنظیم اضافه‌تری ندارد):

ALTER TABLE `bills` DEFAULT CHARACTER SET utf8 COLLATE utf8_persian_ci

برای رفع این مشکل توصیه شده است که CharSet=UTF8 را به رشته اتصالی به بانک اطلاعاتی اضافه کنیم. اما در این حالت خطای زیر ظاهر می‌شود:
The provider did not return a ProviderManifestToken string
این مورد فقط به اشتباه بودن تعاریف رشته اتصالی بر می‌گردد؛‌ یا عدم پشتیبانی از تنظیم اضافه‌ای که در رشته اتصالی ذکر شده است.
مقدار صحیح آن دقیقا مساوی CHARSET=utf8 است (با همین نگارش و رعایت کوچکی و بزرگی حروف؛ مهم!):

<connectionStrings>
<clear/>
<add name="Sample09Context"
connectionString="Datasource=localhost; Database=testdb; Uid=root; Pwd=123;CHARSET=utf8"
providerName="MySql.Data.MySqlClient"/>
</connectionStrings>


به این ترتیب، مشکل ثبت عبارات یونیکد فارسی برطرف می‌شود (البته جدول هم بهتر است به DEFAULT CHARACTER SET utf8 COLLATE utf8_persian_ci تغییر پیدا کند؛ مطابق دستور Alter ایی که در بالا ذکر شد).

نظرات مطالب
مدیریت سفارشی سطوح دسترسی کاربران در MVC

سلام؛ من هم مشکل ایشون دارم و رول‌ها کش نمیشه و هر بار متد GetRolesForUser اجرا میشود. اون هم نه یکبار بلکه به تعداد زیاد و بار زیادی به دیتابیس وارد می‌کنه. لینک شما هم پیغام زیر و میدهد:

An update is available for the .NET Framework 4.5 in Windows 7 SP1, Windows Server 2008 R2 SP1, Windows Server 2008 SP2, and Windows Vista SP2: January 2013

اما ویندوز من 8 هست و پیغام سایت برای ویندوزهای 2008و7وvista هستش. با گشتن هم دیدم بعضی‌ها خودشون متد را دستی کش کردن

        public override string[] GetRolesForUser(string username)
        {
            var cacheKey = string.Format("{0}:{1}", username, ApplicationName);
            var cache = HttpContext.Current.Cache;
            var roles = cache[cacheKey] as string[];
            if (null == roles)
            {              
                using (var db = new Uas3Context())
                {
                    var u = new EfStudentService(db);
                    roles=u.GetUserRoles(username);
                    cache.Insert(cacheKey, roles, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration);                    
                }
            }
            return roles;
        }

اما این متد و من کش کردم باقی متدها چی؟ کل متدها را همین طوری کش کنم؟ این کد هم به نظرم ناقصه . چون با تغییر دیتابیس به روز نمیشه و صرفا درصورت وجود کش اطلاعات می‌خونه. اصلا چرا در دات نت 4.5 این مشکل هست و چرا بر روی ویندوز 8 این پیغام داده میشود؟

اشتراک‌ها
سری حسابرسی SQL Server

This continues my series on auditing SQL Server. The fist parts covered discovery and documentation, server level hardware audits and SQL Server engine level audits. This section examines database configuration audits.

سری حسابرسی SQL Server
اشتراک‌ها
معرفی SQL Server بر روی Linux

 Today I’m excited to announce our plans to bring SQL Server to Linux as well. This will enable SQL Server to deliver a consistent data platform across Windows Server and Linux, as well as on-premises and cloud. 

معرفی SQL Server بر روی Linux
نظرات مطالب
تنظیمات پیشنهادی حداکثر حافظه‌ی مصرفی اس کیوال سرور
برای IIS حدود حداقل یک گیگ و اگر تعداد کاربر زیاد است تا یک و نیم گیگ را کنار بگذارید. DNS Server زیاد حافظه مصرف نمی‌کند. یا حداقل به اندازه‌ی IIS نیست. تا 300 مگ برای آن زیاد هم هست.
بنابراین اگر مثلا سرور شما 4 گیگ رم دارد و IIS و DNS و SQL Server و غیره را با هم دارد، حداکثر حافظه مصرفی SQL Server را به حدود 2.3 گیگ محدود کنید و گرنه خیلی زود صدای کاربران سایت‌(ها) در خواهد آمد که باز هم کند شد ... باز هم کند شد ...
اشتراک‌ها
دلایل ارتقاء به SQL Server 2017

Following is a chart that shows licensing cost comparison between standard and Enterprise Edition of SQL Server 2012, 2016 and 2017.

Version Edition License Cost 2 Quad core
Processors
4 Quad core
Processors
    Per Core 8 Cores 16 Cores
SQL Server 2012 Standard $1,793 $14,344 $28,688
SQL Server 2012 Enterprise $6,874 $54,992 $109,984
SQL Server 2016\ 2017 Standard $1,858 $14,864 $29,728
SQL Server 2016 \2017 Enterprise $7,128 $57,024 $114,048
دلایل ارتقاء به SQL Server 2017
مطالب
SQL Injection چیست؟
برای ایجاد امنیت در نرم افزار، باید ابتدا مشکلات رایج را بدانیم. یکی از رایجترین نقائص امنیتی نرم افزارها SQL Injection می‌باشد.
SQL Injection در لغت به معنی تزریق کد SQL می‌باشد. در اصلاح یعنی تزریق دستوراتی به کد SQL تولیدی یک نرم افزار به نحوی که به جای عمل مورد انتظار برنامه نویس آن، کاری را که ما می‌خواهیم انجام دهد. مثلا به جای اینکه هنگام ورود به برنامه وقتی کاربر مشخصات کاربری خود را وارد می‌کند، مشخصات کاربری را به نحوی وارد کنیم که بتوانیم بعنوان مدیر سامانه و یا یک کاربر معمولی بدون داشتن کلمه عبور وارد سیستم شویم.
البته همیشه از این نوع حمله برای ورود به سیستم استفاده نمی‌شود. یعنی ممکن است هکر به عنوان یک کاربر عادی وارد سیستم شود ولی با به کاربردن دستورات خاص SQL در بخش‌های مختلف، بتواند اطلاعاتی را حذف نماید.
خوب حالا این کار چگونه انجام می‌شود؟
فرض کنید برنامه نویسی کد چک نام کاربری را اینگونه نوشته باشد:
SqlCommand cmd=new SqlCommand ("select count(*) from login where user='"+userName+"' and pass='"+password+"'",con);

فکر نکنید خوب این نوع کد نویسی مربوط به زمان تیرکمون شاه است! همین امروز در نظارت از یک پروژه به این نکته برخورد کردم! دلیل نوشتن این مقاله هم همین کد بود.
خوب حالا مگر کد بالا چه مشکلی دارد؟ ;) اگر کاربر در نامه کاربری و کلمه عبور مقادیر معمولی وارد کند (مانند admin, salam123) کد sql تولید شده به شکل زیر خواهد بود:

select count(*) from login where user='admin' and pass='salam123'

خوب حالا اگر کاربر کمی با ورودی‌ها بازی کند. به عنوان مثال فرض کنید به جای کلمه عبور تایپ کند
' or 1=1 --

نتیجه حاصله خواهد بود:
select count(*) from login where user='admin' and pass='' or 1=1 --'

با وارد کردن این دستور کاربر بدون داشتن کلمه عبور خواهد توانست وارد سیستم شود. موردی که توضیح دادم پایه مسئله بود. ما قصد آموزش هک نداریم ولی داشتن اطلاعات پایه لازم است. ممکن است فردی بگوید خوب ما قبل از تولید همچین کدی ' را از رشته کلمه عبور حذف می‌کنیم. خیلی خوب ولی اگر هکر از معادل unicode آن استفاده کرد چه؟ اگر و اگر و اگر...
راه حل‌های متعددی برای این موضوع پیشنهاد شده است. ولی ساده‌ترین و کارآمد‌ترین راه، استفاده از پارامترها می‌باشد که علاوه بر حذف این خطر باعث ایجاد و ذخیره query plan در sql server می‌شود و اجرای این query را در آینده تسریع می‌کند.
بنابراین می‌توان کد فوق را به صورت زیر بازنویسی کرد:
SqlCommand cmd=new SqlCommand ("select count(*) from login where user=@u and pass=@p",con);

cmd.Parameters.Add("@u", SqlDbType.Varchar, 10).Value=TextLogin.Text.Trim();

cmd.Parameters.Add("@p", SqlDbType.Varchar,10).Value=TextPwd.Text.Trim();