using KssSmaPlaLib.Batch.Commons; using KssSmaPlaLib.Batch.Interface; using KssSmaPlaLib.Commons; using KssSmaPlaLib.Exchange; using KssSmaPlaLib.Ini; using KssSmaPlaLib.IO.Database; using KssSmaPlaLib.IO.File; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.InteropServices.ComTypes; using System.Text; using System.Threading.Tasks; namespace KssSmaPlaLib.Batch.Exchange { public class CsvToDbStepHandlerUxer { public FuncCsvToDbByIniResultDto TryFuncCsvToDbByIni( string iniFilePath, string sectionName) { const string KEY_SQL_FOLDER_PATH = "SqlFolderPath"; const string KEY_CSV_FILE_NAME_PATTERNS = "CsvFileNamePatterns"; const string KEY_INSERT_SQL_FILES = "InsertSqlFiles"; const string KEY_DUP_CHECK_SQL_FILES = "DupCheckSqlFiles"; const string KEY_DELETE_BEFORE_INSERT_SQL_FILES = "DeleteBeforeInsertSqlFiles"; const string KEY_CSV_ENCODING = "CsvEncoding"; const string KEY_DB_PROVIDER_NAME = "DbProviderName"; const string KEY_DB_CONNECTION_STRING = "DbConnectionString"; const string KEY_CSV_FOLDER_PATH = "CsvFolderPath"; var result = new FuncCsvToDbByIniResultDto(); var iniDic = IniReferenceResolveUxer.ReadSectionWithReference(iniFilePath, sectionName); // 開始日 if (!CommonUxer.TryGetStartDate(iniDic, out var startDate, out var messageForMe)) { var msg = $"開始日の取得に失敗しました。[エラー内容:{messageForMe}]"; LoggerUxer.Error(msg); result.Succeeded = false; result.ExitCode = (int)RetCodeUxer.RetCode.StartDateError; result.ResultMessage = msg; return result; } // DB接続確認 if (DbUxer.TestConnectByDic(iniDic, out messageForMe) == false) { var msg = $"DB接続確認で失敗しました。[エラー内容:{messageForMe}]"; LoggerUxer.Error(msg); result.Succeeded = false; result.ExitCode = (int)RetCodeUxer.RetCode.DbConnectError; result.ResultMessage = msg; return result; } LoggerUxer.Info($"DB接続確認が成功しました。[プロバイダ名:{DictionaryUxer.GetValueOrDefault(iniDic, KEY_DB_PROVIDER_NAME, string.Empty)},接続文字列:{DictionaryUxer.GetValueOrDefault(iniDic, KEY_DB_CONNECTION_STRING, string.Empty)}]"); if (!string.IsNullOrEmpty(messageForMe)) { // Infoメッセージがあれば出力 LoggerUxer.Info(messageForMe); } // SQLフォルダパス var sqlFolderPath = DictionaryUxer.GetValueOrDefault(iniDic, KEY_SQL_FOLDER_PATH, string.Empty); if (string.IsNullOrEmpty(sqlFolderPath)) { var msg = $"設定ファイルにSQLフォルダパスが設定されていません。[キー:{KEY_SQL_FOLDER_PATH}]"; LoggerUxer.Error(msg); result.Succeeded = false; result.ExitCode = (int)RetCodeUxer.RetCode.SqlFolderPathNoSetting; result.ResultMessage = msg; return result; } // SQLのロード if (!DbUxer.TryLoadSqlFromText(sqlFolderPath, out messageForMe)) { var msg = $"SQLのロードに失敗しました。[フォルダパス:SQL,エラー内容:{messageForMe}"; LoggerUxer.Error(msg); result.Succeeded = false; result.ExitCode = (int)RetCodeUxer.RetCode.SqlFileLoadError; result.ResultMessage = msg; return result; } LoggerUxer.Info(messageForMe); // 正常メッセージ // CSVファイル名パターン群 var csvPatterns = DictionaryUxer.GetValueOrDefault(iniDic, KEY_CSV_FILE_NAME_PATTERNS, string.Empty); if (string.IsNullOrEmpty(csvPatterns)) { var msg = $"設定ファイルのCSVファイル名パターンが設定されていません。[キー:{KEY_CSV_FILE_NAME_PATTERNS}]"; LoggerUxer.Error(msg); result.Succeeded = false; result.ExitCode = (int)RetCodeUxer.RetCode.CsvFileNamePatternsNotSetting; result.ResultMessage = msg; return result; } var csvPatternArray = csvPatterns.Split(','); // INSERT文SQLファイル群 var insertSqlFiles = DictionaryUxer.GetValueOrDefault(iniDic, KEY_INSERT_SQL_FILES, string.Empty); var insertSqlFilesArray = insertSqlFiles.Split(','); // 重複チェックSELECT文SQLファイル群 var dupCheckSqlFiles = DictionaryUxer.GetValueOrDefault(iniDic, KEY_DUP_CHECK_SQL_FILES, string.Empty); var dupCheckSqlFilesArray = dupCheckSqlFiles.Split(','); // 挿入前の削除SQLファイル群 var deleteBeforeInsertSqlFiles = DictionaryUxer.GetValueOrDefault(iniDic, KEY_DELETE_BEFORE_INSERT_SQL_FILES, string.Empty); var deleteBeforeInsertSqlFilesArray = deleteBeforeInsertSqlFiles.Split(','); // 要素数チェック if (csvPatternArray.Length != insertSqlFilesArray.Length || csvPatternArray.Length != dupCheckSqlFilesArray.Length || csvPatternArray.Length != deleteBeforeInsertSqlFilesArray.Length) { var msg = $"設定ファイルの要素数が異なります。[{KEY_CSV_FILE_NAME_PATTERNS},{KEY_INSERT_SQL_FILES},{KEY_DUP_CHECK_SQL_FILES},{KEY_DELETE_BEFORE_INSERT_SQL_FILES}]"; LoggerUxer.Error(msg); result.Succeeded = false; result.ExitCode = (int)RetCodeUxer.RetCode.IniFileItemCountError; result.ResultMessage = msg; return result; } LoggerUxer.Info($"設定ファイルの要素数が一致しています。[要素数:{csvPatternArray.Length},キー:{KEY_CSV_FILE_NAME_PATTERNS},{KEY_INSERT_SQL_FILES},{KEY_DUP_CHECK_SQL_FILES},{KEY_DELETE_BEFORE_INSERT_SQL_FILES}]"); var encodingTypeName = DictionaryUxer.GetValueOrDefault(iniDic, KEY_CSV_ENCODING, "utf8"); var encodingType = EncodingUxer.GetEncodingType(encodingTypeName); if (encodingType == null) { encodingType = EncodingUxer.EncodingType.Utf8WithoutBom; LoggerUxer.Warn($"CSVエンコーディングタイプ名が不正です。UFT-8で処理します。[キー:{KEY_CSV_ENCODING},値:{encodingTypeName}]"); } try { // DB接続 if (!DbUxer.TryCreateByDic(iniDic, out DbUxer con, out messageForMe, false/* ★★★ トランザクション有無:true */)) { LoggerUxer.Error(messageForMe); result.Succeeded = false; result.ExitCode = (int)RetCodeUxer.RetCode.DbConnectError; result.ResultMessage = messageForMe; return result; } LoggerUxer.Info($"DBに接続しました。[プロバイダ名:{DictionaryUxer.GetValueOrDefault(iniDic, KEY_DB_PROVIDER_NAME, string.Empty)},接続文字列:{DictionaryUxer.GetValueOrDefault(iniDic, KEY_DB_CONNECTION_STRING, string.Empty)}]"); var csvFolderPath = DictionaryUxer.GetValueOrDefault(iniDic, KEY_CSV_FOLDER_PATH, "."); LoggerUxer.Info($"[CSVフォルダパス:{csvFolderPath}]"); using (con) { // CSVパターン毎 for (var cnt = 0; cnt < csvPatternArray.Length; cnt++) { LoggerUxer.Info($"[CSVパターン{cnt + 1}:{csvPatternArray[cnt]}]"); var insertSqlFile = insertSqlFilesArray[cnt]; var csvFileNamePattern = csvPatternArray[cnt]; var dupCheckSqlFile = dupCheckSqlFilesArray[cnt]; var deleteBeforeInsertSqlFile = deleteBeforeInsertSqlFilesArray[cnt]; LoggerUxer.Info($"[該当ファイル数:{Directory.GetFiles(csvFolderPath, csvFileNamePattern).Length}]"); // ファイル毎 foreach (var path in Directory.GetFiles(csvFolderPath, csvFileNamePattern)) { if (deleteBeforeInsertSqlFile == "DeleteBeforeInsertWeOrder") { // 溶接専用!🔥🌊 // 最小日の取得(溶接専用ロジック) var minDic = new Dictionary(); // CSV読み込み+最小値取得 if (!GetMinValueByKeyFromCsvFiles(path, "line_id", "work_date", ref minDic, out var messageForMe0)) { LoggerUxer.Error(messageForMe0); result.Succeeded = false; result.ExitCode = (int)RetCodeUxer.RetCode.InsertDbFromCsvFilesError; result.ResultMessage = messageForMe; return result; } LoggerUxer.Info($"ライン毎の最小日の取得を完了"); if (!string.IsNullOrEmpty(deleteBeforeInsertSqlFile)) { // 挿入前の削除SQLを実行 LoggerUxer.Info($"挿入前の削除SQLを実行[SQLファイル:{deleteBeforeInsertSqlFile}]"); var totalResultCount = 0; foreach (var kv in minDic) { var resultCount = 0; if (!con.ExecuteNonQuery( deleteBeforeInsertSqlFile, new Dictionary() { { "LINE_ID", kv.Key }, { "START_DATE", kv.Value } }, out resultCount, out messageForMe)) { var msg = $"挿入前の削除が失敗しました。[エラー内容:{messageForMe}]"; LoggerUxer.Error(msg); result.Succeeded = false; result.ExitCode = (int)RetCodeUxer.RetCode.DeleteBeforeInsertException; result.ResultMessage = msg; return result; } totalResultCount += resultCount; LoggerUxer.Info($"挿入前の削除成功[ラインID:{kv.Key},開始日:{kv.Value},削除件数:{resultCount}]"); } LoggerUxer.Info($"挿入前の削除SQLを完了[更新件数:{totalResultCount}]"); } else { LoggerUxer.Info($"挿入前の削除処理はSQLが未指定のためスキップしました。[キー:{KEY_DELETE_BEFORE_INSERT_SQL_FILES}]"); } } else { if (!string.IsNullOrEmpty(deleteBeforeInsertSqlFile)) { // 挿入前の削除SQLを実行 LoggerUxer.Info($"挿入前の削除SQLを実行[SQLファイル:{deleteBeforeInsertSqlFile}]"); var totalResultCount = 0; if (!con.ExecuteNonQuery( deleteBeforeInsertSqlFile, new Dictionary() { { "START_DATE", startDate } }, out var resultCount, out messageForMe)) { var msg = $"挿入前の削除が失敗しました。[エラー内容:{messageForMe}]"; LoggerUxer.Error(msg); result.Succeeded = false; result.ExitCode = (int)RetCodeUxer.RetCode.DeleteBeforeInsertException; result.ResultMessage = msg; return result; } totalResultCount += resultCount; LoggerUxer.Info($"挿入前の削除SQLを完了[更新件数:{totalResultCount}]"); } else { LoggerUxer.Info($"挿入前の削除処理はSQLが未指定のためスキップしました。[キー:{KEY_DELETE_BEFORE_INSERT_SQL_FILES}]"); } } // CSV読み込み+DB挿入 LoggerUxer.Info($"CSV読み込み+DB挿入を実行[ファイルパス:{path}]"); if (!CsvDbSyncUxer.InsertDbFromCsvFiles(iniDic, con, path, dupCheckSqlFile, insertSqlFile, out messageForMe, (EncodingUxer.EncodingType)encodingType)) { LoggerUxer.Error(messageForMe); result.Succeeded = false; result.ExitCode = (int)RetCodeUxer.RetCode.InsertDbFromCsvFilesError; result.ResultMessage= messageForMe; return result; } LoggerUxer.Info($"CSV読み込み+DB挿入を完了"); } } // コミット con.Commit(); } LoggerUxer.Info($"DB処理が完了し、DB接続を終了しました。"); } catch (Exception ex) { var msg = $"DB処理にてエラーが発生しました。[エラー内容:{ex.Message}]"; LoggerUxer.Error(msg); result.Succeeded = false; result.ExitCode = (int)RetCodeUxer.RetCode.CsvToDbException; result.ResultMessage = msg; return result; } result.Succeeded = true; return result; } /// /// CSVよりキー毎に最小値を取得し辞書で返す /// /// /// /// /// /// /// /// /// /// public static bool GetMinValueByKeyFromCsvFiles( string csvFilePath, string keyColName, string valueColName, ref Dictionary minDic, out string resultMessage, EncodingUxer.EncodingType encodingType = EncodingUxer.EncodingType.Utf8WithoutBom) where TKeyType : IComparable where TValueType : IComparable { // 👇参照型(追記とする)ゆえやめた //minDic = new Dictionary(); resultMessage = string.Empty; try { // CSV読み込み if (!CsvUxer.ImportFromCsv(csvFilePath, out var rs, out var messageForMe, encodingType)) { resultMessage = messageForMe; return false; } //LoggerUxer.Info($"[CSV件数:{rs.Count}]"); foreach (var rec in rs) { TKeyType key; TValueType val; try { key = (TKeyType)Convert.ChangeType(rec[keyColName], typeof(TKeyType)); } catch (Exception) { continue; }; try { val = (TValueType)Convert.ChangeType(rec[valueColName], typeof(TValueType)); } catch (Exception) { continue; } if (minDic.ContainsKey(key)) { minDic[key] = Comparer.Default.Compare(val, minDic[key]) < 0 ? val : minDic[key]; } else { minDic[key] = val; } } return true; } catch (Exception ex) { resultMessage = $"最小日時取得時にエラーが発生しました。[エラー内容:{ex.Message}]"; return false; } } } public class FuncCsvToDbByIniResultDto : IFuncResultDto { public bool Succeeded { get; set; } = false; public int ExitCode { get; set; } = 0; public string ResultMessage { get; set; } = string.Empty; } }