/// <summary> /// 引数に指定したDtDeviceでDT_DEVICEテーブルを更新する /// </summary> /// <param name="inData">更新するデータ</param> /// <returns>更新したデータ</returns> public DtDevice UpdateDtDevice(DtDevice inData) { DtDevice model = null; try { _logger.EnterJson("{0}", inData); DBAccessor.Models.DtDevice entity = new DBAccessor.Models.DtDevice(inData); _dbPolly.Execute(() => { using (DBAccessor.Models.RmsDbContext db = new DBAccessor.Models.RmsDbContext(_appSettings)) { // 指定SIDのデータがDBになければnullリターン if (db.DtDevice.AsNoTracking().FirstOrDefault(x => x.Sid == inData.Sid) == null) { return; } db.DtDevice.Attach(entity); // 全フィールドを更新する // 特定フィールドだけUpdateする場合は下記のように記述してください // db.Entry(entity).Property(x => x.UpdateDatetime).IsModified = true; db.Entry(entity).Property(x => x.InstallTypeSid).IsModified = true; db.Entry(entity).Property(x => x.EquipmentModelSid).IsModified = true; if (db.SaveChanges(_timePrivder) > 0) { // 呼び出し側に更新済みデータを返却する model = db.DtDevice.AsNoTracking().FirstOrDefault(x => x.Sid == inData.Sid)?.ToModel(); } } }); return(model); } catch (ValidationException e) { throw new RmsParameterException(e.ValidationResult.ErrorMessage, e); } catch (Exception e) { throw new RmsException("DT_DEVICEテーブルのUpdateに失敗しました。", e); } finally { _logger.LeaveJson("{0}", model); } }
/// <summary> /// デバイスツイン更新イベントを受信して端末テーブルの「リモート接続UID」と「RMSソフトバージョン」を更新する /// </summary> /// <param name="sid">端末SID</param> /// <param name="data">更新データ</param> /// <returns>更新したデータ。テーブルが更新されなかった場合にはnullを返す</returns> public DtDevice UpdateDeviceInfoByTwinChanged(long sid, DtTwinChanged data) { DtDevice model = null; try { _logger.EnterJson("{0}", sid); _dbPolly.Execute(() => { using (DBAccessor.Models.RmsDbContext db = new DBAccessor.Models.RmsDbContext(_appSettings)) { string remoteConnectionUid = data.RemoteConnectionUid; string rmsSoftVersion = data.SoftVersion; // リモート接続UIDとRMSソフトバージョンを更新する DtDevice inData = new DtDevice() { Sid = sid, RemoteConnectUid = remoteConnectionUid, RmsSoftVersion = rmsSoftVersion }; DBAccessor.Models.DtDevice entity = new DBAccessor.Models.DtDevice(inData); db.DtDevice.Attach(entity); // リモート接続UIDとRMSソフトバージョンを更新する db.Entry(entity).Property(x => x.RemoteConnectUid).IsModified = true; db.Entry(entity).Property(x => x.RmsSoftVersion).IsModified = true; if (db.SaveChanges(_timePrivder) > 0) { model = entity.ToModel(); } } }); return(model); } catch (ValidationException e) { throw new RmsParameterException(e.ValidationResult.ErrorMessage, e); } catch (Exception e) { throw new RmsException("DT_DEVICEテーブルのUpdateに失敗しました。", e); } finally { _logger.LeaveJson("{0}", model); } }
/// <summary> /// データの更新(配信ステータスが「配信前」の時のみ) /// 実際の更新処理を行う /// </summary> /// <param name="inData">更新データ</param> /// <returns>更新されたDB内容</returns> private DtDeliveryGroup UpdateIfNotStart(DtDeliveryGroup inData) { using (DBAccessor.Models.RmsDbContext db = new DBAccessor.Models.RmsDbContext(_appSettings)) { try { // 指定した配信グループSIDと一致する情報を取得する var entity = db.DtDeliveryGroup .Include(x => x.DeliveryGroupStatusS) .FirstOrDefault(x => x.Sid == inData.Sid); if (entity == null) { return(null); } // 指定した配信ステータスSIDを検索し、未配信状態であるかチェックする var isNotStart = entity.DeliveryGroupStatusS.Code.Equals(Utility.Const.DeliveryGroupStatus.NotStarted); if (!isNotStart) { throw new RmsCannotChangeDeliveredFileException(string.Format("配信前状態ではないDT_DELIVERY_GROUPテーブルのレコードをUpdateしようとしました。(DT_DELIVERY_GROUP.SID = {0})", inData.Sid)); } // 情報の更新 entity.Name = inData.Name; entity.StartDatetime = inData.StartDatetime; entity.DownloadDelayTime = inData.DownloadDelayTime; // コンテキスト管理のRowVersionを投入値に置き換えて、DBデータと比較させる(Attatch処理以外では必要) db.Entry(entity).Property(e => e.RowVersion).OriginalValue = inData.RowVersion; var p = db.DtDeliveryGroup.Update(entity); db.SaveChanges(_timePrivder); return(p.Entity.ToModel()); } catch (ValidationException e) { throw new RmsParameterException(e.ValidationResult.ErrorMessage, e); } catch (DbUpdateConcurrencyException e) { // RowVersion衝突が起きた throw new RmsConflictException("DT_DELIVERY_GROUPテーブルのUpdateで競合が発生しました。", e); } catch { // SqlExceptionであれば再試行される throw; } } }
/// <summary> /// 引数に指定したDtSmartAnalysisResultでDT_SMART_ANALYSIS_RESULTテーブルを更新する /// </summary> /// <param name="inData">更新するデータ</param> /// <returns>更新したデータ</returns> public DtSmartAnalysisResult UpdateDtSmartAnalysisResult(DtSmartAnalysisResult inData) { DtSmartAnalysisResult model = null; try { _logger.EnterJson("{0}", inData); DBAccessor.Models.DtSmartAnalysisResult entity = new DBAccessor.Models.DtSmartAnalysisResult(inData); // バリデーション Validator.ValidateObject(entity, new ValidationContext(entity, null, null)); _dbPolly.Execute(() => { entity.UpdateDatetime = _timePrivder.UtcNow; using (DBAccessor.Models.RmsDbContext db = new DBAccessor.Models.RmsDbContext(_appSettings)) { db.DtSmartAnalysisResult.Attach(entity); // 全フィールドを更新する // 特定フィールドだけUpdateする場合は下記のように記述してください // db.Entry(entity).Property(x => x.UpdateDatetime).IsModified = true; db.Entry(entity).State = Microsoft.EntityFrameworkCore.EntityState.Modified; if (db.SaveChanges() > 0) { model = entity.ToModel(); } } }); return(model); } catch (ValidationException e) { throw new RmsParameterException(e.ValidationResult.ErrorMessage, e); } catch (Exception e) { throw new RmsException("DT_SMART_ANALYSIS_RESULTテーブルのUpdateに失敗しました。", e); } finally { _logger.LeaveJson("{0}", model); } }
/// <summary> /// DT_PARENT_CHILD_CONNECTテーブルにメッセージを追加またはメッセージの内容で更新処理を行う(親フラグ=trueの場合) /// </summary> /// <param name="inData">更新データ</param> /// <returns>追加または更新したデータ。「確認日時」が既存レコードより古く更新しなかった場合には、nullを返す</returns> public DtParentChildConnect Save(DtParentChildConnectFromParent inData) { DtParentChildConnect model = null; try { _dbPolly.Execute(() => { using (DBAccessor.Models.RmsDbContext db = new DBAccessor.Models.RmsDbContext(_appSettings)) using (var tran = db.Database.BeginTransaction()) { // 現在時刻を取得 var now = _timePrivder.Now; // メッセージクラス→Modelクラス変換時に、通信が成功だった場合は最終接続日時にデータが格納される // ここで初期値だった場合には通信失敗と判断できる if (inData.ParentLastConnectDatetime == null || inData.ParentLastConnectDatetime == default(DateTime)) { inData.ParentLastConnectDatetime = now; } // DB格納データクラス DBAccessor.Models.DtParentChildConnect entity = CreateEntityFromParent(inData, db); // 親機器 - 子機器 - 親機器確認結果の組み合わせをチェックする // 3つの組み合わせでレコードを一意に決めることができる var sids = CreateSqlParameterSet(entity.ParentDeviceSid, entity.ChildDeviceSid); DBAccessor.Models.DtParentChildConnect targetRecord = db.DtParentChildConnect.FromSql(SelectParentSqlCommand, sids).AsNoTracking().FirstOrDefault(); if (targetRecord == null || targetRecord.Sid == 0) { // 作成日時+更新日時 // 通常はSaveChangesにTimeProvideを渡し、DBが自動的に作成日時と更新日時を設定する。 // しかし親子間通信データについては、 // 通信失敗のケースにおいて最終更新日時にはレコード作成日時を格納する // (nullを回避しつつ、通信失敗ケースであったことを後から判断できるようにするため)。 // DBが自動的に時刻を設定した場合に、リポジトリ内で取得した時刻と時間差が発生する可能性があるため、 // リポジトリ内で明示的に時刻を取得してDBにレコードを挿入する。 entity.CreateDatetime = now; entity.UpdateDatetime = now; // レコード追加 var dbdata = db.DtParentChildConnect.Add(entity).Entity; // 最終日時更新データと作成日時・更新日時を一致させたいので、TimeProviderは渡さずに明示的な日時データを使う db.SaveChanges(); model = dbdata.ToModel(); } else { // データの時刻チェック: データがDBに格納されたデータよりも新しい場合のみ更新処理を行う // DBよりも古い確認時刻だった場合には更新せずにnullを返す DateTime?dbTime = targetRecord.ParentConfirmDatetime; if (dbTime == null || inData.ParentConfirmDatetime.Value.CompareTo(dbTime.Value) > 0) { // 更新対象のレコードのSIDを設定 entity.Sid = targetRecord.Sid; db.DtParentChildConnect.Attach(entity); // 更新のあったデータのみを更新する db.Entry(entity).Property(x => x.ParentConfirmDatetime).IsModified = true; db.Entry(entity).Property(x => x.ParentResult).IsModified = true; if (entity.ParentResult != null && entity.ParentResult.Value) { db.Entry(entity).Property(x => x.ParentLastConnectDatetime).IsModified = true; } db.SaveChanges(_timePrivder); model = entity.ToModel(); } } // トランザクション終了 tran.Commit(); } }); return(model); } catch (ValidationException e) { throw new RmsParameterException(e.ValidationResult.ErrorMessage, e); } catch (Exception e) { throw new RmsException("DT_PARENT_CHILD_CONNECTテーブルの更新処理に失敗しました。", e); } finally { _logger.LeaveJson("{0}", model); } }
/// <summary> /// 引数に指定したDtPlusServiceBillLogをDT_PLUS_SERVICE_BILL_LOGテーブルへ登録する /// </summary> /// <param name="inData">登録するデータ</param> /// <returns>追加したデータ。エラーが発生した場合には例外を投げるためnullを返さない</returns> public DtPlusServiceBillLog Upsert(DtPlusServiceBillLog inData) { DtPlusServiceBillLog model = null; try { _logger.EnterJson("{0}", inData); DBAccessor.Models.DtPlusServiceBillLog entity = new DBAccessor.Models.DtPlusServiceBillLog(inData); _dbPolly.Execute(() => { using (DBAccessor.Models.RmsDbContext db = new DBAccessor.Models.RmsDbContext(_appSettings)) { // 重複チェック var existing = db.DtPlusServiceBillLog .FirstOrDefault(x => x.StudyInstanceUid == inData.StudyInstanceUid && x.TypeName == inData.TypeName); if (existing == null) { // 追加 db.DtPlusServiceBillLog.Add(entity); } else { // 計測日時が古いデータで更新しないようにする。 // 呼び出し側のパラメタチェックでかかるはずだが、 // 日時がnullableなので念のため既存日時がnullの場合は更新するようにしておく。 if (existing.MeasureDatetime < inData.MeasureDatetime || existing.MeasureDatetime == null) { // 更新処理 entity.Sid = existing.Sid; db.DtPlusServiceBillLog.Attach(entity); db.Entry(entity).Property(x => x.DeviceSid).IsModified = true; db.Entry(entity).Property(x => x.SourceEquipmentUid).IsModified = true; //// db.Entry(entity).Property(x => x.TypeName).IsModified = true; db.Entry(entity).Property(x => x.BillFlg).IsModified = true; db.Entry(entity).Property(x => x.PatientId).IsModified = true; db.Entry(entity).Property(x => x.Sex).IsModified = true; db.Entry(entity).Property(x => x.Age).IsModified = true; //// db.Entry(entity).Property(x => x.StudyInstanceUid).IsModified = true; db.Entry(entity).Property(x => x.SopInstanceUid).IsModified = true; db.Entry(entity).Property(x => x.StudyDatetime).IsModified = true; db.Entry(entity).Property(x => x.MeasureDatetime).IsModified = true; db.Entry(entity).Property(x => x.CollectDatetime).IsModified = true; db.Entry(entity).Property(x => x.UpdateDatetime).IsModified = true; } else { // 古いデータでの更新を弾く、AlreadyExistとはニアリーイコールではあるが、丸める new RmsAlreadyExistException(string.Format("StudyInstanceUid [{0}], TypeName[{1}] はすでに追加済みです。", inData.StudyInstanceUid, inData.TypeName)); } } if (db.SaveChanges(_timePrivder) > 0) { // 呼び出し側に更新済みデータを返却する model = db.DtPlusServiceBillLog.FirstOrDefault(x => x.Sid == inData.Sid)?.ToModel(); } } }); return(model); } catch (RmsAlreadyExistException) { throw; } catch (ValidationException e) { throw new RmsParameterException(e.ValidationResult.ErrorMessage, e); } catch (Exception e) { throw new RmsException("DT_PLUS_SERVICE_BILL_LOGテーブルへのInsertに失敗しました。", e); } finally { _logger.LeaveJson("{0}", model); } }
/// <summary> /// データの更新(配信ステータスが「配信前」の時のみ) /// 実際の更新処理を行う /// </summary> /// <param name="inData">更新データ</param> /// <param name="isSame">更新要否の判定メソッド</param> /// <param name="updater">更新メソッド</param> /// <param name="option">更新処理オプション</param> /// <returns>更新されたDB内容</returns> private DtDeliveryFile Update( DtDeliveryFile inData, Func <DBAccessor.Models.DtDeliveryFile, DtDeliveryFile, bool> isSame, Func <DBAccessor.Models.RmsDbContext, DBAccessor.Models.DtDeliveryFile, DtDeliveryFile, DBAccessor.Models.DtDeliveryFile> updater, UpdateOption option) { // 複数回のSQL実行を競合なく実行・ロールバックさせるためにトランザクションを用いる using (DBAccessor.Models.RmsDbContext db = new DBAccessor.Models.RmsDbContext(_appSettings)) using (var tran = db.Database.BeginTransaction()) { try { var entity = db.DtDeliveryFile .Include(x => x.DtDeliveryModel) .FirstOrDefault(x => x.Sid == inData.Sid); if (entity == null) { return(null); } // isSame()の結果同一と判定されたら更新不要のため処理終了 if (isSame(entity, inData)) { return(entity.ToModel()); } if (option == UpdateOption.OnlyNotStart) { // 指定した配信ファイルSIDを持つ配信グループを検索し、そのすべての配信ステータスが未配信状態であるかチェックする var isAllNotStarted = db.DtDeliveryGroup .Where(x => x.DeliveryFileSid == inData.Sid) .Include(x => x.DeliveryGroupStatusS) .All(x => x.DeliveryGroupStatusS.Code.Equals(Utility.Const.DeliveryGroupStatus.NotStarted)); if (!isAllNotStarted) { throw new RmsCannotChangeDeliveredFileException(string.Format("配信前状態ではないDT_DELIVERY_FILEテーブルのレコードをUpdateしようとしました。(DT_DELIVERY_FILE.SID = {0})", inData.Sid)); } } // 情報の更新 entity = updater(db, entity, inData); // コンテキスト管理のRowVersionを投入値に置き換えて、DBデータと比較させる(Attatch処理以外では必要) db.Entry(entity).Property(e => e.RowVersion).OriginalValue = inData.RowVersion; var p = db.DtDeliveryFile.Update(entity); db.SaveChanges(); // トランザクション終了 tran.Commit(); return(p.Entity.ToModel()); } catch (ValidationException e) { throw new RmsParameterException(e.ValidationResult.ErrorMessage, e); } catch (DbUpdateConcurrencyException e) { // RowVersion衝突が起きた tran.Rollback(); throw new RmsConflictException("DT_DELIVERY_FILEテーブルのUpdateで競合が発生しました。", e); } catch { // SqlExceptionであれば再試行される tran.Rollback(); throw; } } }
/// <summary> /// 配信結果ステータスを更新する /// </summary> /// <param name="gatewaySid">最上位(ゲートウェイ)機器SID</param> /// <param name="statusCode">ステータス</param> /// <returns>結果</returns> /// <remarks>ステータスはUtility.Consts.InstallResultStatusに定義されている</remarks> private DtInstallResult UpdateInstallResultStatus(long gatewaySid, string statusCode) { DtInstallResult model = null; try { _logger.EnterJson("{0}", new { gatewaySid, statusCode }); _dbPolly.Execute(() => { using (DBAccessor.Models.RmsDbContext db = new DBAccessor.Models.RmsDbContext(_appSettings)) { DBAccessor.Models.DtInstallResult entity = null; // 更新対象レコードを取得する entity = db.DtInstallResult.Where(x => /*x.IsLatest &&*/ x.DeliveryResultS.GwDeviceSid == gatewaySid).FirstOrDefault(); if (entity == null || entity.Sid == 0) { // 対象レコードなしエラー throw new RmsException("更新対象となる適用結果データレコードが見つかりませんでした。"); } // 「送信済」の適用結果ステータスSIDを取得する var status = db.MtInstallResultStatus.Where(x => x.Code.Equals(statusCode)).FirstOrDefault(); if (status == null || status.Sid == 0) { // 対象レコードなしエラー throw new RmsException("指定したステータスコードが.MT_INSTALL_RESULT_STATUSテーブルに存在しませんでした。"); } // ステータスSIDを更新 entity.InstallResultStatusSid = status.Sid; // DB更新処理 db.DtInstallResult.Attach(entity); db.Entry(entity).Property(x => x.InstallResultStatusSid).IsModified = true; if (db.SaveChanges() > 0) { model = entity.ToModel(); } db.SaveChanges(_timePrivder); model = entity.ToModel(); } }); return(model); } catch (ValidationException e) { throw new RmsParameterException(e.ValidationResult.ErrorMessage, e); } catch (Exception e) { throw new RmsException("DT_INSTALL_RESULTテーブルへのInsertに失敗しました。", e); } finally { _logger.LeaveJson("{0}", model); } }
/// <summary> /// 端末テーブルの接続ステータスを更新する /// </summary> /// <param name="sid">端末SID</param> /// <param name="connectionEventTimeInfo">接続/切断イベント時刻情報</param> /// <returns>更新したデータ。ステータスに変更がなかった場合にはnullを返す</returns> public DtDevice UpdateDeviceConnectionStatus(long sid, ConnectionEventTimeInfo connectionEventTimeInfo) { DtDevice model = null; try { _logger.EnterJson("{0}", sid); _dbPolly.Execute(() => { using (DBAccessor.Models.RmsDbContext db = new DBAccessor.Models.RmsDbContext(_appSettings)) { // 該当するステータスSIDをマスタテーブルから取得する var record = db.MtConnectStatus.FirstOrDefault(x => x.Code == connectionEventTimeInfo.Status); if (record == null || record.Sid == 0) { throw new RmsException("接続ステータスマスターテーブルに該当するステータスが存在しませんでした。"); } // ステータスSID, 接続開始日時, 接続更新日時 DtDevice inData = new DtDevice() { Sid = sid, ConnectStatusSid = record.Sid, ConnectStartDatetime = connectionEventTimeInfo.EventTime, ConnectUpdateDatetime = connectionEventTimeInfo.EventTime }; DBAccessor.Models.DtDevice entity = new DBAccessor.Models.DtDevice(inData); db.DtDevice.Attach(entity); // 接続ステータスが更新されるのでステータスSIDと接続更新日時は更新対象 db.Entry(entity).Property(x => x.ConnectStatusSid).IsModified = true; db.Entry(entity).Property(x => x.ConnectUpdateDatetime).IsModified = true; // 初回接続フラグがtrueのときは接続開始日時も更新対象 if (connectionEventTimeInfo.IsFirstConnection) { db.Entry(entity).Property(x => x.ConnectStartDatetime).IsModified = true; } if (db.SaveChanges(_timePrivder) > 0) { model = entity.ToModel(); } } }); return(model); } catch (ValidationException e) { throw new RmsParameterException(e.ValidationResult.ErrorMessage, e); } catch (Exception e) { throw new RmsException("DT_DEVICEテーブルのUpdateに失敗しました。", e); } finally { _logger.LeaveJson("{0}", model); } }