2018年9月18日 星期二

ASP.NET Core 2.1 with MySQL raw SQL

情境:
有個案子使用 ASP.NET Core 2.1 建立 API 撈取 MySQL 資料,使用 "Pomelo.EntityFrameworkCore.MySql" 套件,操作和預設的 EntityFramework Core 一樣。

現在有一案例,客戶提供 MySQL statement 要撈取想要的資料,statement 中有 "UNION ALL",我試著轉成 Linq ,"UNION ALL" 的部分使用 "IQueryable<T>.Contact(IQueryable<T>)",在執行時發生錯誤,如果改為 "IEnumerable<T>.Contact(IEnumerable<T>)" 則可正常執行,估計這套件無法將 "IQueryable<T>.Contact(IQueryable<T>)" 轉換成正確的 MySQL statement "UNION ALL",考慮到效能所以不使用"IEnumerable<T>.Contact(IEnumerable<T>)",因此決定使用 raw SQL

            var result = new List<MyReportViewModel>();
            var ym = $"{model.Year}-{(model.Month < 10 ? "0" : "")}{model.Month}";
            using (var command = _context.Database.GetDbConnection().CreateCommand())
            {
                command.CommandText = $@"
SELECT *
FROM 
(
  {GenerateJasperMySql(ym)}

  UNION ALL

  {GenerateJasperMySql(ym, "STATEHISTORY")}

)AS SOURCE
ORDER BY object_name, start_time ASC
";
                _context.Database.OpenConnection();
                using (var reader = command.ExecuteReader())
                {
                    if (reader.HasRows)
                    {
                        while (reader.Read())
                        {
                            result.Add(new MyReportViewModel
                            {
                                object_type = (string)reader["object_type"],
                                object_id = reader.GetInt32(1),
                                object_name = (string)reader["object_name"],
                                object_service = (string)reader["object_service"],
                                start_time = (string)reader["start_time"],
                                end_time = (string)reader["end_time"],
                                object_state = (string)reader["object_state"],
                                output = (string)reader["output"],
                            });
                        }
                    }
                }
            }
            return result;

備註:
_context : 依賴注入的 DbContext
GenerateJasperMySql() : 因為 "UNION ALL" 的兩個 SQL statement 類似,因此設計這個 method 來產生
參考 使用 DataReader 擷取資料