Files
HLib/Batch/Exchange/CsvToDbStepHandlerUxer.cs
T
2026-06-01 13:23:34 +09:00

358 lines
18 KiB
C#

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<int, DateTime>();
// CSV読み込み+最小値取得
if (!GetMinValueByKeyFromCsvFiles<int, DateTime>(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<string, object>()
{
{ "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<string, object>()
{
{ "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;
}
/// <summary>
/// CSVよりキー毎に最小値を取得し辞書で返す
/// </summary>
/// <typeparam name="TKeyType"></typeparam>
/// <typeparam name="TValueType"></typeparam>
/// <param name="csvFilePath"></param>
/// <param name="keyColName"></param>
/// <param name="valueColName"></param>
/// <param name="minDic"></param>
/// <param name="resultMessage"></param>
/// <param name="encodingType"></param>
/// <returns></returns>
public static bool GetMinValueByKeyFromCsvFiles<TKeyType, TValueType>(
string csvFilePath,
string keyColName,
string valueColName,
ref Dictionary<TKeyType, TValueType> minDic,
out string resultMessage,
EncodingUxer.EncodingType encodingType = EncodingUxer.EncodingType.Utf8WithoutBom)
where TKeyType : IComparable<TKeyType>
where TValueType : IComparable<TValueType>
{
// 👇参照型(追記とする)ゆえやめた
//minDic = new Dictionary<TKeyType, TValueType>();
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<TValueType>.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;
}
}