یک نکتهی تکمیلی: اهمیت دقت داشتن به امضای متد FromSql در EF Core 2.0
در EF Core 2.0، اگر از String Interpolation معرفی شدهی در C# 6.0 استفاده شود، متد FromSql این نوع متغیرها را به صورت خودکار تبدیل به پارامترهای کوئریهای SQL میکند. برای مثال کوئری ذیل که در آن userName از طریق String Interpolation معرفی شدهاست:
یک چنین خروجی SQL ایی را تولید میکند:
همانطور که ملاحظه میکنید پارامتر p0@ به صورت خودکار بجای {userName} درج شدهاست.
اما ... اگر این کوئری را به نحو ذیل اجرا کنیم:
برنامه کرش میکند:
علت اینجا است که زمانیکه رشتهی Interpolation را مستقیما داخل متد FromSql درج میکنیم از overload زیر استفاده میکند:
در اینجا sql از نوع FormattableString معرفی شدهاست.
اما زمانیکه از var استفاده میکنیم، یعنی این رشته به نوع string تبدیل میشود. در این حالت دیگر از overload فوق استفاده نشده و عملیات تهیهی کوئریهای پارامتری انجام نخواهد شد. علت کرش برنامه هم همین مورد است. اگر در این حالت بخواهیم از userName استفاده کنیم، باید آنرا داخل '' محصور کنیم:
و در نهایت کوئری تولید شده نیز پارامتری نیست:
به عبارتی این نوع کوئری، مستعد به حملات تزریق اس کیوال است. چون بجای user 1 هر نوع ورودی دیگری را نیز میتوان درج کرد و به علت پارامتری نبودن، این نوع ورودیها میتوانند ساختار عبارت SQL نوشته شده را تغییر دهند.
بنابراین در حین کار با متد FromSql به overload در حال استفاده دقت داشته باشید. فقط حالت FormattableString آن است که کار تبدیل String Interpolation را به کوئریهای پارامتری انجام میدهد.
در EF Core 2.0، اگر از String Interpolation معرفی شدهی در C# 6.0 استفاده شود، متد FromSql این نوع متغیرها را به صورت خودکار تبدیل به پارامترهای کوئریهای SQL میکند. برای مثال کوئری ذیل که در آن userName از طریق String Interpolation معرفی شدهاست:
var userName = "user 1"; var user = context.Users.FromSql($"select top 1 * from Users where name = {userName} ").FirstOrDefault(); if (user != null) { Console.WriteLine(user.Name); }
SELECT TOP(1) [u].[UserId], [u].[IsAdmin], [u].[Name] FROM ( select top 1 * from Users where name = @p0 ) AS [u]
اما ... اگر این کوئری را به نحو ذیل اجرا کنیم:
var sql = $"select top 1 * from Users where name = {userName} "; user = context.Users.FromSql(sql).FirstOrDefault(); if (user != null) { Console.WriteLine(user.Name); }
.SqlException: Incorrect syntax near '1'
public static IQueryable<TEntity> FromSql<TEntity>(this IQueryable<TEntity> source, FormattableString sql) where TEntity : class;
اما زمانیکه از var استفاده میکنیم، یعنی این رشته به نوع string تبدیل میشود. در این حالت دیگر از overload فوق استفاده نشده و عملیات تهیهی کوئریهای پارامتری انجام نخواهد شد. علت کرش برنامه هم همین مورد است. اگر در این حالت بخواهیم از userName استفاده کنیم، باید آنرا داخل '' محصور کنیم:
var sql = $"select top 1 * from Users where name = '{userName}' ";
SELECT TOP(1) [u].[UserId], [u].[IsAdmin], [u].[Name] FROM ( select top 1 * from Users where name = 'user 1' ) AS [u]
بنابراین در حین کار با متد FromSql به overload در حال استفاده دقت داشته باشید. فقط حالت FormattableString آن است که کار تبدیل String Interpolation را به کوئریهای پارامتری انجام میدهد.