โซลูชันนี้ให้ความสำคัญกับโซลูชันจาก @pius ฉันต้องการเพิ่มตัวเลือกเพื่อสนับสนุนพารามิเตอร์การสืบค้นเพื่อช่วยลดการแทรก SQL และฉันยังต้องการทำให้เป็นส่วนขยายจาก DbContext DatabaseFacade สำหรับ Entity Framework Core เพื่อให้รวมเข้าด้วยกันได้มากขึ้น
ขั้นแรกให้สร้างคลาสใหม่โดยใช้ส่วนขยาย:
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Threading.Tasks;
namespace EF.Extend
{
public static class ExecuteSqlExt
{
public static List<T> ExecuteSqlRawExt<T, P>(this DatabaseFacade db, string query, Func<DbDataReader, T> map, IEnumerable<P> queryParameters = null)
{
using (var command = db.GetDbConnection().CreateCommand())
{
if((queryParameters?.Any() ?? false))
command.Parameters.AddRange(queryParameters.ToArray());
command.CommandText = query;
command.CommandType = CommandType.Text;
db.OpenConnection();
using (var result = command.ExecuteReader())
{
var entities = new List<T>();
while (result.Read())
{
entities.Add(map(result));
}
return entities;
}
}
}
}
}
โปรดทราบในด้านบนว่า "T" คือประเภทของผลตอบแทนและ "P" คือประเภทของพารามิเตอร์การสืบค้นของคุณซึ่งจะแตกต่างกันไปตามว่าคุณกำลังใช้ MySql, Sql เป็นต้น
ต่อไปเราจะแสดงตัวอย่าง ฉันใช้ความสามารถ MySql EF Core ดังนั้นเราจะดูว่าเราสามารถใช้ส่วนขยายทั่วไปด้านบนกับการใช้งาน MySql ที่เฉพาะเจาะจงมากขึ้นได้อย่างไร:
using EF.Extend;
namespace Car.Api.Controllers
{
public class Car
{
public string Make { get; set; }
public string Model { get; set; }
public string DisplayTitle { get; set; }
}
[ApiController]
public class CarController : ControllerBase
{
private readonly ILogger<CarController> _logger;
private readonly CarContext _context;
public CarController(ILogger<CarController> logger, CarContext context)
{
_logger = logger;
_context = context;
}
[HttpGet]
public IEnumerable<Car> Get()
{
MySqlParameter p1 = new MySqlParameter
{
ParameterName = "id1",
Value = "25"
};
MySqlParameter p2 = new MySqlParameter
{
ParameterName = "id2",
Value = "26"
};
MySqlParameter p3 = new MySqlParameter
{
ParameterName = "id3",
Value = "27"
};
List<MySqlParameter> queryParameters = new List<MySqlParameter>() { p1, p2, p3 };
List<Car> result = _context.Database.ExecuteSqlRawExt<Car, MySqlParameter>(
"SELECT Car.Make, Car.Model, CONCAT_WS('', Car.Make, ' ', Car.Model) As DisplayTitle FROM Car WHERE Car.Id IN(@id1, @id2, @id3)",
x => new Car { Make = (string)x[0], Model = (string)x[1], DisplayTitle = (string)x[2] },
queryParameters);
return result;
}
}
}
คำค้นหาจะแสดงแถวเช่น
"Ford", "Explorer", "Ford Explorer"
"Tesla", "Model X", "Tesla Model X"
ชื่อที่แสดงไม่ได้กำหนดเป็นคอลัมน์ฐานข้อมูลดังนั้นจะไม่เป็นส่วนหนึ่งของโมเดล EF Car โดยค่าเริ่มต้น ฉันชอบแนวทางนี้เป็นหนึ่งในวิธีแก้ปัญหาที่เป็นไปได้มากมาย คำตอบอื่น ๆ ในหน้านี้อ้างอิงวิธีอื่นในการแก้ไขปัญหานี้กับมัณฑนากร [NotMapped] ซึ่งขึ้นอยู่กับกรณีการใช้งานของคุณอาจเป็นแนวทางที่เหมาะสมกว่า
สังเกตว่าโค้ดในตัวอย่างนี้มีรายละเอียดมากกว่าที่จำเป็น แต่ฉันคิดว่ามันทำให้ตัวอย่างชัดเจนขึ้น