FromSql (và FromSqlInterpolated) nhận chuỗi nội suy nhưng không nối chuỗi: mỗi {...} được EF chuyển thành một DbParameter riêng.
Vì vậy nó an toàn trước SQL injection theo thiết kế.
var orders = await db.Orders
.FromSql($"SELECT * FROM orders WHERE customer_code = {code}")
.ToListAsync();
// -> SELECT * FROM orders WHERE customer_code = @p0FromSqlRaw nhận chuỗi thô.
Nếu nối biến vào chuỗi thì giá trị người dùng đi thẳng vào câu SQL — đây chính là lỗ hổng injection:
// vulnerable
db.Orders.FromSqlRaw("SELECT * FROM orders WHERE customer_code = '" + code + "'");
// safe
db.Orders.FromSqlRaw("SELECT * FROM orders WHERE customer_code = {0}", code);Một bẫy nữa: EF chỉ parse placeholder khi format string được viết inline ngay tại lời gọi. Khai báo chuỗi ở biến bên ngoài rồi truyền vào FromSql thì không còn cơ chế tham số hoá.
Ghi nhớ thực dụng: mặc định dùng FromSql; chỉ dùng FromSqlRaw khi phần SQL động là tên bảng/cột — mà tên bảng/cột thì không tham số hoá được, nên phải whitelist thay vì lấy trực tiếp từ input. Với câu không trả về entity, dùng ExecuteSqlAsync / SqlQuery<T>.