using HotelPms.Data; using HotelPms.Data.Common.Pagination; using HotelPms.Data.Master; using HotelPms.GrpcService.Util; using HotelPms.Share.Data; using HotelPms.Share.IO; using HotelPms.Share.Util; using Google.Protobuf; using Grpc.Core; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using System.Data; using System.Data.SqlClient; using System.Text; using System.Text.Json; using System.Threading.Tasks; namespace HotelPms.GrpcService { /// /// ■攻略 /// 1.Output.proto(message:Output、OutputTable;Service:OutputCore) ⇒ projectファイルのInclude /// 2.Output.cs(両方) /// 3.OutputTable.cs(両方) /// 4.OutputService.cs(サーバー側) ⇒ StartupでMapGrpcServiceの処理が必要 /// 5.OutputAccess.cs(クライアント側) /// public class OutputService : OutputCore.OutputCoreBase { #region ★★★★★ Declartions ★★★★★ public enum EActionType : int { Master = 0, Page = 1, Xlsx = 2, Xls = 3, Pdf = 4, Csv = 5, Json = 6, Xml = 7, DefOutput = 8, } private static string TableName = "M_Output"; private readonly ILogger _logger; private IConfiguration m_Configuration; #endregion #region ★★★★★ Property ★★★★★ #endregion #region ★★★★★ Class Event ★★★★★ public OutputService(ILogger logger, IConfiguration configuration) { _logger = logger; m_Configuration = configuration; } #endregion #region ★★★★★ Private Function ★★★★★ private string GetSql(DataRequest request) { StringBuilder sql = new StringBuilder(); if (request.ActionType == (int)EActionType.Master) { sql.Append($"SELECT * FROM {TableName} {(string.IsNullOrEmpty(request.Data) ? string.Empty : $"WHERE {request.Data}")}"); } else if (request.ActionType >= (int)EActionType.Page && request.ActionType <= (int)EActionType.Xml) { PagingRequest pagingRequest = JsonSerializer.Deserialize(request.Data); sql.Append($"EXEC Pagination {pagingRequest.PageNumber},{pagingRequest.PageSize},'{pagingRequest.Table}','{pagingRequest.Field}','{pagingRequest.OrderBy}','{CConvert.FromBase64(pagingRequest.Filter)}'"); } else if (request.ActionType == (int)EActionType.DefOutput) { sql.Append($"EXEC GetDefaultOuput {request.Data}"); } return sql.ToString(); } private DataTable GetDataTable(DataRequest request) { //ActionType、Dataの組み合わせでデータを取得する DataTable table = null; OperationLog.Instance.WriteLog($"データ請求:{request.ToString()}"); using (MsSqlNet msSqlNet = new MsSqlNet(Setting.HotelPmsDB)) { string sql = GetSql(request); // 全部データの出力(頁変更なし) if (request.ActionType >= (int)EActionType.Xlsx && request.ActionType <= (int)EActionType.Xml) { using (DataSet set = msSqlNet.GetDataSet(sql)) { if (set == null || set.Tables.Count == 0) { OperationLog.Instance.WriteLog("null"); } else { if (set.Tables.Count == 2) { table = set.Tables[0]; } } } } } OperationLog.Instance.WriteLog("データ読込完了"); return table; } /// /// マスタデータのセット /// /// /// /// private void SetMaster(MsSqlNet msSqlNet, string sql, OutputTable table) { using (SqlConnection dbConnect = msSqlNet.Open()) { using (SqlCommand command = new SqlCommand(sql, dbConnect)) { OperationLog.Instance.WriteLog($"データ読込:{sql}"); command.CommandTimeout = 60000 * 100; using (SqlDataReader reader = command.ExecuteReader(CommandBehavior.Default)) { //エラーまだ対応していない if (reader == null) { OperationLog.Instance.WriteLog("null"); table.ErrNo = msSqlNet.ErrNo; table.ErrData = msSqlNet.ErrInfo; } else { while (reader.Read()) { Output item = new Output(); item.ConvertReader(reader); table.Rows.Add(item); } } reader.Close(); } } } } /// /// 頁毎データのセット /// /// /// /// private void SetPage(MsSqlNet msSqlNet, string sql, OutputTable table) { using (DataSet set = msSqlNet.GetDataSet(sql)) { if (set == null || set.Tables.Count == 0) { OperationLog.Instance.WriteLog("null"); table.ErrNo = msSqlNet.ErrNo; table.ErrData = msSqlNet.ErrInfo; } else { if (set.Tables.Count == 2) { foreach (DataRow row in set.Tables[0].Rows) { Output item = new Output(); item.ConvertDataRow(row); table.Rows.Add(item); } table.Tag = JsonSerializer.Serialize(new PagingRespone() { MaxPage = CConvert.ToInt(set.Tables[1].Rows[0]["MaxPage"]), TotalRow = CConvert.ToInt(set.Tables[1].Rows[0]["TotalRow"]) }); } else { table.ErrNo = -1; table.ErrData = set.Tables[0].Rows[0]["Descript"].ToString(); } } } } /// /// ディフォルト列設定をセット /// /// /// /// private void SetDefOutput(MsSqlNet msSqlNet, string sql, OutputTable table) { using (DataSet set = msSqlNet.GetDataSet(sql)) { if (set == null || set.Tables.Count == 0) { OperationLog.Instance.WriteLog("null"); table.ErrNo = msSqlNet.ErrNo; table.ErrData = msSqlNet.ErrInfo; } else { Output output = new Output(); output.ConvertDataRow(set.Tables[0].Rows[0]); table.Rows.Add(output); foreach (DataRow row in set.Tables[1].Rows) { OutputItem item = new OutputItem(); item.ConvertDataRow(row); output.Items.Add(item); } // 表示名称 ⇒ フィールド名のマッピング // ※存在しなかったら、表示名称 = フィールド名ということ foreach (DataRow row in set.Tables[2].Rows) { output.FieldMap.Add(row["Name"].ToString(), row["Field"].ToString()); } foreach (DataRow row in set.Tables[3].Rows) { output.SelectList.Add(CConvert.ToInt(row["ID"]), row["Name"].ToString()); } } } } /// /// ActionTypeによるデータ取得 /// /// /// private OutputTable Get(DataRequest request) { //ActionType、Dataの組み合わせでデータを取得する OutputTable table = new OutputTable() { ErrNo = 0, ErrData = string.Empty, Name = nameof(OutputTable) }; OperationLog.Instance.WriteLog($"データ請求:{request.ToString()}"); using (MsSqlNet msSqlNet = new MsSqlNet(Setting.HotelPmsDB)) { string sql = GetSql(request); if (request.ActionType == (int)EActionType.Master) { SetMaster(msSqlNet, sql, table); } else if (request.ActionType == (int)EActionType.Page) { SetPage(msSqlNet, sql, table); } else if (request.ActionType == (int)EActionType.DefOutput) { SetDefOutput(msSqlNet, sql, table); } } OperationLog.Instance.WriteLog("データ読込完了"); return table; } private DataResult Set(OutputTable table) { DataResult result = new DataResult() { ErrNo = 0, ErrData = string.Empty }; OperationLog.Instance.WriteLog($"データ請求:{table.Rows.Count}"); StringBuilder sql = new StringBuilder(); if (table.BeforeUpdate.Length > 0) { sql.AppendLine(table.BeforeUpdate.ToStringUtf8()); } foreach (Output item in table.Rows) { sql.AppendLine(table.UpdateType == 2 ? item.UpdateSql() : item.AddSql()); } if (table.AfterUpdate.Length > 0) { sql.AppendLine(table.AfterUpdate.ToStringUtf8()); } string sqlCmd = sql.ToString(); OperationLog.Instance.WriteLog($"Sql生成:{sqlCmd}"); using (MsSqlNet msSqlNet = new MsSqlNet(Setting.HotelPmsDB)) { if (!msSqlNet.ExecuteNonQueryWithTran(sqlCmd)) { result.ErrNo = msSqlNet.ErrNo; result.ErrData = msSqlNet.ErrInfo; } } OperationLog.Instance.WriteLog($"更新:{result.ToString()}"); return result; } private DataResult AddOrUpdate(bool add, Output item) { DataResult result = new DataResult() { ErrNo = 0, ErrData = string.Empty }; OperationLog.Instance.WriteLog($"データ請求:{item.ToString()}"); using (MsSqlNet msSqlNet = new MsSqlNet(Setting.HotelPmsDB)) { StringBuilder sql = new StringBuilder(); if (add) { int id = CConvert.ToInt(msSqlNet.ExecuteScalar(item.MaxIDSql())) + 1; item.ID = id; } else { sql.AppendLine(item.ClearDetailSql()); } sql.AppendLine(add ? item.AddSql() : item.UpdateSql()); int i = 1; foreach (OutputItem detail in item.Items) { detail.MachineName = item.MachineName; detail.UserName = item.UserName; detail.ReportID = item.ReportID; detail.OutputID = item.ID; detail.ID = i; sql.AppendLine(detail.AddSql()); i++; } OperationLog.Instance.WriteLog($"Sql生成:{sql}"); if (!msSqlNet.ExecuteNonQueryWithTran(sql.ToString())) { result.ErrNo = msSqlNet.ErrNo; result.ErrData = msSqlNet.ErrInfo; } } OperationLog.Instance.WriteLog($"更新:{result.ToString()}"); return result; } private async Task AddOrUpdate(bool add, IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context) { Output item = null; await foreach (var message in requestStream.ReadAllAsync()) { item = message; break; } DataResult result = AddOrUpdate(add, item); await responseStream.WriteAsync(result); //データ送信 } private DataResult Delete(SqlWhere item) { DataResult result = new DataResult() { ErrNo = 0, ErrData = string.Empty }; OperationLog.Instance.WriteLog($"データ請求:{item.ToString()}"); string sql = $@"DELETE FROM M_OutputItem WHERE OutputID IN (SELECT ID FROM {TableName} WHERE {item.Data.ToStringUtf8()}); DELETE FROM {TableName} WHERE {item.Data.ToStringUtf8()};"; OperationLog.Instance.WriteLog($"Sql生成:{sql}"); using (MsSqlNet msSqlNet = new MsSqlNet(Setting.HotelPmsDB)) { if (!msSqlNet.ExecuteNonQueryWithTran(sql)) { result.ErrNo = msSqlNet.ErrNo; result.ErrData = msSqlNet.ErrInfo; } } OperationLog.Instance.WriteLog($"更新:{result.ToString()}"); return result; } #endregion #region ★★★★★ Public Function ★★★★★ public async override Task OutputStream(DataRequest request, IServerStreamWriter responseStream, ServerCallContext context) { try { using (DataTable data = GetDataTable(request)) { byte[] bytes = Excel.Export(data); FileGrpcData fileGrpcData = new FileGrpcData { Block = 1, FileName = "Data", Content = ByteString.CopyFrom(bytes) }; await responseStream.WriteAsync(fileGrpcData); } } catch { } } /// /// 同期実行 /// /// /// /// public override Task GetData(DataRequest request, ServerCallContext context) { return Task.FromResult(Get(request)); } public async override Task GetDataStream(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context) { DataRequest request = null; await foreach (var message in requestStream.ReadAllAsync()) { request = message; break; } OutputTable table = Get(request); await responseStream.WriteAsync(table); //データ送信 } public override Task SetData(OutputTable request, ServerCallContext context) { return Task.FromResult(Set(request)); } public async override Task SetDataStream(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context) { OutputTable table = null; await foreach (var message in requestStream.ReadAllAsync()) { table = message; break; } DataResult result = Set(table); //データ送信 await responseStream.WriteAsync(result); } public override Task Add(Output request, ServerCallContext context) { return Task.FromResult(AddOrUpdate(true, request)); } public async override Task AddStream(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context) { await AddOrUpdate(true, requestStream, responseStream, context); } public override Task Update(Output request, ServerCallContext context) { return Task.FromResult(AddOrUpdate(false, request)); } public async override Task UpdateStream(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context) { await AddOrUpdate(false, requestStream, responseStream, context); } public override Task Remove(SqlWhere request, ServerCallContext context) { return Task.FromResult(Delete(request)); } public async override Task RemoveStream(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context) { SqlWhere item = null; await foreach (var message in requestStream.ReadAllAsync()) { item = message; break; } DataResult result = Delete(item); await responseStream.WriteAsync(result); //データ送信 } #endregion } }