// Copyright (c) 2015-present schick Informatik // Description: Container für alle Meldeklassen using System; using System.Data; using System.Data.SqlClient; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using Newtonsoft.Json; namespace bsmd.database { /// /// Basisklasse aller Nachrichtentypen, zentrale Klasse für die NSW App /// public class Message : DatabaseEntity, ISublistContainer, IComparable { #region Fields private ReportingParty reportingParty; #endregion #region ANSWSortList public static IList ANSWSortList = new ReadOnlyCollection( new List{ NotificationClass.TIEFA, NotificationClass.POBA, NotificationClass.BKRA, NotificationClass.TOWA, NotificationClass.NOA_NOD, NotificationClass.STAT, NotificationClass.NAME, NotificationClass.INFO, NotificationClass.SERV, NotificationClass.LADG, NotificationClass.TIEFD, NotificationClass.POBD, NotificationClass.BKRD, NotificationClass.TOWD, NotificationClass.SEC, NotificationClass.PRE72H, NotificationClass.BPOL, NotificationClass.CREWA, NotificationClass.PASA, NotificationClass.MDH, NotificationClass.HAZA, NotificationClass.HAZD, NotificationClass.WAS, NotificationClass.ATA, NotificationClass.ATD, NotificationClass.AGNT, NotificationClass.STO, NotificationClass.CREWD, NotificationClass.PASD }); #endregion #region Enumerations /// /// NSW notification class /// public enum NotificationClass { VISIT, // 0 TRANSIT, // 1 NOA_NOD, // 2 ATA, ATD, SEC, // 5 POBA, POBD, NAME, TIEFA, TIEFD, // 10 BKRA, BKRD, STAT, LADG, INFO, // 15 SERV, PRE72H, MDH, WAS, CREWA, // 20 PASA, BPOL, TOWA, TOWD, HAZA, // 25 HAZD, AGNT, STO, // DK - only CREWD, PASD, WAS_RCPT } public enum MessageStatus { ACCEPTED, REJECTED } /// /// Anhand dieses Filters und den Parametern können die Klassen das passende LoadQuery generieren /// public enum LoadFilter { ALL, MESSAGETYPE, REPORTINGPARTY, MESSAGEHEADER, BSMDSTATUS, WETRIS_SHIP_ID, MDH_ID, POC30_ID, WAS_ID, WDSP_ID, BPOL_ID, SEC_ID, HERBERG_FORMGUID, BY_ID, BY_CORE, NOA_NODID, HAZ_ID, IMDG_ID, REPORTSTATUS, IMO_ETA_POC, BY_VISITID, BY_TRANSITID, BY_CORE_ENI, BY_CORE_EXCEL, BY_CORE_HE, CREATE_EXCEL, SEARCH_CORE_FILTERS, QUERY_NSW_STATUS, NOT_DELETED, DELETED, IMPORTHEADER_ID, BY_CORE_AND_CLASS, BY_AGE, WASRCPT_ID, BY_FILE_SEQ_NUM, BY_TYPE } /// /// Message Status einer NSW Einzelnachricht /// public enum BSMDStatus { UNDEFINED = 0, PREPARE, TOSEND, SENT, SEND_FAILED, CONFIRMED, VIOLATION, ERROR, SUSPENDED = 8, IN_USE, UPDATED, REPORT, // nur für diese Meldeklasse einen PDF Report erzeugen (geht danach wieder auf PREPARE) SAVED, // veränderte Meldeklasse wird im ENI gespeichert EXCEL // Meldeklasse wurde in Excel befüllt } /// /// Spezifiziert das gewünschte HIS zur Übertragung der Daten /// public enum NSWProvider { [Description("Unspecified")] UNDEFINED, DBH, DAKOSY, [Description("HIS-Nord")] DUDR, [Description("dbh / Maersk")] DBH_MAERSK } // Late to the party: generic flags Enum/Field [Flags] public enum MessageFlags : int { NONE = 0, UNSENT_WARNING_SHOWN = 1, UNCONFIRMED_WARNING_SHOWN = 2 } #endregion #region Construction public Message() { this.tablename = "[dbo].[MessageHeader]"; } #endregion #region Properties /// /// Dieser Wert wird vom NSW / HIS vergeben /// public string ClientRequestId { set; get; } public Guid? MessageId { get; set; } public Guid? MessageCoreId { get; set; } public DateTime? SentAt { get; set; } public string SentBy { get; set; } public DateTime? ReceivedAt { get; set; } public DateTime? RequestedAt { get; set; } public bool Reset { get; set; } public bool Cancel { get; set; } public MessageStatus? Status { get; set; } [ShowReport] public DateTime? Created { get; private set; } /// /// Vorwärts-Referenzen auf die von diesem Header-Element abhängigen speziellen Nachrichten-Datensätzen /// Folgende Objekte können pro Nachricht n-fach vorkommen /// BRKA, BRKD, LADG, CREW, PAS, SERV, TOWA, TOWD, STO, CREWD, PASD /// sonst hat die Liste immer ein Element /// public ObservableCollection Elements { get; } = new ObservableCollection(); /// /// Der Meldende /// public ReportingParty ReportingParty { get { return this.reportingParty; } set { if (value == null) { this.ReportingPartyId = null; } else { this.ReportingPartyId = value.Id; } this.reportingParty = value; } } /// /// Status für Services /// public BSMDStatus InternalStatus { get; set; } /// /// Display helper property for overview status /// public string BSMDStatusOverviewDisplay { get { return (InternalStatus != BSMDStatus.UNDEFINED) ? InternalStatus.ToString() : ""; } } /// /// Vorheriger Status (z.B. für nach der Report-Generierung), wird nicht immer gesetzt /// public BSMDStatus? LastStatus { get; set; } /// /// Erweiterte Erläuterung für Status(-wechsel) zur Darstellung im ENI /// public string StatusInfo { get; set; } /// /// die zur Kommunikation zu verwendende HIS Schnittstelle /// public NSWProvider HIS { get; set; } /// /// Display helper property for overview HIS /// public string HISOverviewDisplay { get { return (HIS != NSWProvider.UNDEFINED) ? HIS.ToString() : string.Empty; } } /// /// Fehlerliste (Rückgabe vom NSW) /// public List ErrorList { get; } = new List(); /// /// Violation-Liste (Rückgabe vom NSW) /// public List ViolationList { get; } = new List(); /// /// Liste mit "System"-Errors (HIS-Nord) /// public List SystemErrorList { get; } = new List(); /// /// Property to overwrite reporting party in certain circumstances (other melder meldet) /// public Guid? ReportingPartyId { get; set; } /// /// Urheber der Nachricht (Excel oder HE) /// public string CreatedBy { get; set; } /// /// Bearbeiter für Änderungshistorie (=Name des angemeldeten Melders), wird vom ENI-2 Speicherprozess befüllt /// public string ChangedBy { get; set; } /// /// Database last "Changed" date display /// public DateTime? Changed { get; private set; } /// /// ENI-2 detail group text /// public string ENINotificationDetailGroup { get; set; } /// /// Hilfsproperty zum schnellen Auffinden der passenden Gruppe /// public int ENINotificationDetailIndex { get; set; } /// /// Hilfsproperty zum Speichern des Icon-Pfads in ENI-2 /// public string ENINotificationIconString { get; set; } /// /// ENI Display flag /// public bool HasErrors { get { return !this.ErrorList.IsNullOrEmpty(); } } /// /// ENI Display flag /// public bool HasViolations { get { return !this.ViolationList.IsNullOrEmpty(); } } /// /// Flag zeigt an ob unbearbeitete ImportValues für die Meldeklasse vorhanden sind /// public bool HasUpdates { get; set; } /// /// ENI Display flag /// public bool HasSystemErrors { get { return !this.SystemErrorList.IsNullOrEmpty(); } } /// /// Flag zeigt an ob ein Benutzer einen Reminder für ein Feld der Meldeklasse gesetzt hat /// public bool HasReminder { get; set; } /// /// ENI display flag: send complete /// public bool SuccessfullySent { get { return this.SystemErrorList.IsNullOrEmpty() && this.ViolationList.IsNullOrEmpty() && this.ErrorList.IsNullOrEmpty() && this.Status.HasValue && !this.Reset && (this.Status.Value == MessageStatus.ACCEPTED); } } /// /// Dieses Flag wird gesetzt, sobald die Meldeklasse *einmal* erfolgreich gesendet wurde. Es bleibt bestehen, auch /// wenn ein nachfolgender Sendevorgang auf einen Fehler läuft. Neue Interpretation (10.11.17): /// Das Flag bedeutet, dass beim NSW Inhalte hinterlegt sind /// -> bei einem erfolgreichen Reset muss das Flag wieder zurück gesetzt werden /// public bool? SendSuccess { get; set; } public bool UnsentMessageWarningShown { get { return this.IsFlagSet(MessageFlags.UNSENT_WARNING_SHOWN); } set { this.SetFlag(value, MessageFlags.UNSENT_WARNING_SHOWN); } } public bool UnconfirmedMessageWarningShown { get { return this.IsFlagSet(MessageFlags.UNCONFIRMED_WARNING_SHOWN); } set { this.SetFlag(value, MessageFlags.UNCONFIRMED_WARNING_SHOWN); } } /// /// Speicher-Int für generische Flags /// public int Flags { get; set; } /// /// If message was sent via dbh, this is the consecutive number used in the file name, /// null if unused /// public int? FileSequenceNumber { get; set; } /// /// Number of violations during last validation /// public int? ViolationCount { get; set; } /// /// Number of violations during last validation that have the "identifier" set and are thus detected violations /// from underlying list elements /// public int? PositionViolationCount { get; set; } /// /// Number of errors during last validation /// public int? ErrorCount { get; set; } #endregion #region IDatabaseEntity implementation public override void PrepareSave(IDbCommand dbCommand) { SqlCommand cmd = dbCommand as SqlCommand; if (this.ClientRequestId != null) cmd.Parameters.AddWithValue("@CLIENTREQUESTID", Guid.Parse(this.ClientRequestId)); else cmd.Parameters.AddWithValue("@CLIENTREQUESTID", DBNull.Value); cmd.Parameters.AddWithValue("@MESSAGECOREID", this.MessageCore.Id); if (this.MessageId.HasValue) cmd.Parameters.AddWithValue("@MESSAGEID", this.MessageId.Value); else cmd.Parameters.AddWithValue("@MESSAGEID", DBNull.Value); if (this.SentAt.HasValue) cmd.Parameters.AddWithValue("@SENTAT", this.SentAt.Value); else cmd.Parameters.AddWithValue("@SENTAT", DBNull.Value); if (this.ReceivedAt.HasValue) cmd.Parameters.AddWithValue("@RECEIVEDAT", this.ReceivedAt.Value); else cmd.Parameters.AddWithValue("@RECEIVEDAT", DBNull.Value); if (this.RequestedAt.HasValue) cmd.Parameters.AddWithValue("@REQUESTEDAT", this.RequestedAt.Value); else cmd.Parameters.AddWithValue("@REQUESTEDAT", DBNull.Value); cmd.Parameters.AddWithValue("@NOTIFICATIONCLASS", (int)this.MessageNotificationClass); cmd.Parameters.AddWithValue("@RESET", this.Reset); cmd.Parameters.AddWithValue("@CANCEL", this.Cancel); if (this.Status.HasValue) cmd.Parameters.AddWithValue("@STATUS", (int)this.Status.Value); else cmd.Parameters.AddWithValue("@STATUS", DBNull.Value); cmd.Parameters.AddWithNullableValue("@REPORTINGPARTYID", this.ReportingPartyId); cmd.Parameters.AddWithValue("@BSMDSTATUS", this.InternalStatus); cmd.Parameters.AddWithNullableValue("@LASTSTATUS", this.LastStatus); cmd.Parameters.AddWithValue("@HIS", this.HIS); cmd.Parameters.AddWithNullableValue("@CREATEDBY", this.CreatedBy); cmd.Parameters.AddWithNullableValue("@CHANGEDBY", this.ChangedBy); cmd.Parameters.AddWithNullableValue("@STATUSINFO", this.StatusInfo); cmd.Parameters.AddWithNullableValue("@SENDSUCCESS", this.SendSuccess); cmd.Parameters.AddWithNullableValue("@SENTBY", this.SentBy); cmd.Parameters.AddWithValue("@FLAGS", this.Flags); cmd.Parameters.AddWithNullableValue("@FILESEQNUM", this.FileSequenceNumber); if (this.IsNew) { this.CreateId(); cmd.Parameters.AddWithValue("@ID", this.Id); string query = string.Format("INSERT INTO {0} (Id, ClientRequestId, MessageCoreId, MessageId, SentAt, ReceivedAt, RequestedAt, NotificationClass, Reset, Cancel, Status, ReportingPartyId, BSMDStatus, LastStatus, HIS, CreatedBy, ChangedBy, StatusInfo, SendSuccess, SentBy, Flags, FileNumSequence) " + "VALUES (@ID, @CLIENTREQUESTID, @MESSAGECOREID, @MESSAGEID, @SENTAT, @RECEIVEDAT, @REQUESTEDAT, @NOTIFICATIONCLASS, @RESET, @CANCEL, @STATUS, @REPORTINGPARTYID, @BSMDSTATUS, @LASTSTATUS, @HIS, @CREATEDBY, @CHANGEDBY, @STATUSINFO, @SENDSUCCESS, @SENTBY, @FLAGS, @FILESEQNUM)", this.Tablename); cmd.CommandText = query; } else { cmd.Parameters.AddWithValue("@ID", this.Id); cmd.CommandText = string.Format("UPDATE {0} SET ClientRequestId = @CLIENTREQUESTID, MessageId = @MESSAGEID, SentAt = @SENTAT, ReceivedAt = @RECEIVEDAT, RequestedAt = @REQUESTEDAT, " + "NotificationClass = @NOTIFICATIONCLASS, Reset = @RESET, Cancel = @CANCEL, Status = @STATUS, ReportingPartyId = @REPORTINGPARTYID, BSMDStatus = @BSMDSTATUS, LastStatus = @LASTSTATUS, HIS = @HIS, " + "CreatedBy = @CREATEDBY, ChangedBy = @CHANGEDBY, StatusInfo = @STATUSINFO, SendSuccess = @SENDSUCCESS, SentBy = @SENTBY, Flags = @FLAGS, FileNumSequence = @FILESEQNUM WHERE Id = @ID", this.Tablename); } } public override void PrepareLoadCommand(IDbCommand cmd, LoadFilter filter, params object[] criteria ) { string query = string.Format("SELECT Id, ClientRequestId, MessageCoreId, MessageId, SentAt, ReceivedAt, RequestedAt, NotificationClass, " + "Reset, Cancel, Status, ReportingPartyId, BSMDStatus, LastStatus, HIS, Created, CreatedBy, ChangedBy, Changed, StatusInfo, SendSuccess, SentBy, Flags, FileNumSequence FROM {0} ", this.Tablename); switch (filter) { case LoadFilter.REPORTINGPARTY: { query += "WHERE ReportingPartyId = @RPID"; ((SqlCommand)cmd).Parameters.AddWithValue("RPID", criteria[0]); break; } case LoadFilter.BSMDSTATUS: { query += "WHERE BSMDStatus = @BSMDSTATUS"; ((SqlCommand)cmd).Parameters.AddWithValue("@BSMDSTATUS", criteria[0]); break; } case LoadFilter.BY_ID: { query += "WHERE Id = @ID"; ((SqlCommand)cmd).Parameters.AddWithValue("@ID", criteria[0]); break; } case LoadFilter.BY_CORE: { query += "WHERE MessageCoreId = @COREID"; ((SqlCommand)cmd).Parameters.AddWithValue("@COREID", criteria[0]); break; } case LoadFilter.BY_CORE_ENI: { query += "WHERE MessageCoreId = @COREID AND ChangedBy IS NOT NULL"; ((SqlCommand)cmd).Parameters.AddWithValue("@COREID", criteria[0]); break; } case LoadFilter.BY_CORE_EXCEL: { query += "WHERE MessageCoreId = @COREID AND CreatedBy = 'EXCEL'"; ((SqlCommand)cmd).Parameters.AddWithValue("@COREID", criteria[0]); break; } case LoadFilter.BY_CORE_HE: { query += "WHERE MessageCoreId = @COREID AND (CreatedBy = 'HE' OR CreatedBy IS NULL)"; // TODO: letzte Bedingung nach Übergangsphase entfernen ((SqlCommand)cmd).Parameters.AddWithValue("@COREID", criteria[0]); break; } case LoadFilter.BY_CORE_AND_CLASS: { query += "WHERE MessageCoreId = @COREID AND NotificationClass = @CLASS"; ((SqlCommand)cmd).Parameters.AddWithValue("@COREID", criteria[0]); ((SqlCommand)cmd).Parameters.AddWithValue("@CLASS", criteria[1]); break; } case LoadFilter.BY_FILE_SEQ_NUM: { query += "WHERE FileNumSequence = @FILESEQNUM"; ((SqlCommand)cmd).Parameters.AddWithValue("@FILESEQNUM", criteria[0]); break; } case LoadFilter.ALL: default: break; } cmd.CommandText = query; } public override List LoadList(IDataReader reader) { List result = new List(); while (reader.Read()) { Message msg = new Message(); msg.id = reader.GetGuid(0); if (!reader.IsDBNull(1)) msg.ClientRequestId = reader.GetGuid(1).ToString(); msg.MessageCoreId = reader.GetGuid(2); if(!reader.IsDBNull(3)) msg.MessageId = reader.GetGuid(3); if (!reader.IsDBNull(4)) msg.SentAt = reader.GetDateTime(4); if (!reader.IsDBNull(5)) msg.ReceivedAt = reader.GetDateTime(5); if (!reader.IsDBNull(6)) msg.RequestedAt = reader.GetDateTime(6); if (!reader.IsDBNull(7)) msg.MessageNotificationClass = (NotificationClass) Enum.ToObject(typeof(NotificationClass), reader.GetByte(7)); if (!reader.IsDBNull(8)) msg.Reset = reader.GetBoolean(8); if (!reader.IsDBNull(9)) msg.Cancel = reader.GetBoolean(9); if (!reader.IsDBNull(10)) msg.Status = (MessageStatus)Enum.ToObject(typeof(MessageStatus), reader.GetByte(10)); if (!reader.IsDBNull(11)) msg.ReportingPartyId = reader.GetGuid(11); if (!reader.IsDBNull(12)) msg.InternalStatus = (BSMDStatus)Enum.ToObject(typeof(BSMDStatus), reader.GetByte(12)); if (!reader.IsDBNull(13)) msg.LastStatus = (BSMDStatus)Enum.ToObject(typeof(BSMDStatus), reader.GetByte(13)); if (!reader.IsDBNull(14)) msg.HIS = (NSWProvider)Enum.ToObject(typeof(NSWProvider), reader.GetByte(14)); if (!reader.IsDBNull(15)) msg.Created = reader.GetDateTime(15); if (!reader.IsDBNull(16)) msg.CreatedBy = reader.GetString(16); if (!reader.IsDBNull(17)) msg.ChangedBy = reader.GetString(17); if (!reader.IsDBNull(18)) msg.Changed = reader.GetDateTime(18); if (!reader.IsDBNull(19)) msg.StatusInfo = reader.GetString(19); if (!reader.IsDBNull(20)) msg.SendSuccess = reader.GetBoolean(20); if (!reader.IsDBNull(21)) msg.SentBy = reader.GetString(21); if (!reader.IsDBNull(22)) msg.Flags = reader.GetInt32(22); if (!reader.IsDBNull(23)) msg.FileSequenceNumber = reader.GetInt32(23); result.Add(msg); } reader.Close(); return result; } #endregion #region public static helpers public static void AssignReportingParties(List messages, Dictionary reportingParties) { foreach (Message message in messages) { if (message.ReportingPartyId.HasValue && reportingParties.ContainsKey(message.ReportingPartyId.Value)) message.reportingParty = reportingParties[message.ReportingPartyId.Value]; } } public static void AssignMessageCores(List messages, Dictionary messageCores) { foreach (Message message in messages) { if (message.MessageCoreId.HasValue && messageCores.ContainsKey(message.MessageCoreId.Value)) message.MessageCore = messageCores[message.MessageCoreId.Value]; } } public static bool IsListClass(NotificationClass notificationClass) { switch(notificationClass) { case NotificationClass.BKRA: case NotificationClass.BKRD: case NotificationClass.CREWA: case NotificationClass.CREWD: case NotificationClass.LADG: case NotificationClass.PASA: case NotificationClass.PASD: case NotificationClass.SERV: case NotificationClass.STO: case NotificationClass.TOWA: case NotificationClass.TOWD: case NotificationClass.WAS_RCPT: return true; } return false; } /// /// Some message classes are (currently) skipped for validation /// public bool EvaluateForValidation(bool isTransit) { bool result = true; switch (this.MessageNotificationClass) { case NotificationClass.BKRD: case NotificationClass.PRE72H: case NotificationClass.TIEFD: case NotificationClass.NAME: case NotificationClass.INFO: case NotificationClass.ATA: case NotificationClass.ATD: case NotificationClass.LADG: case NotificationClass.SERV: case NotificationClass.WAS: case NotificationClass.TOWD: case NotificationClass.HAZD: case NotificationClass.WAS_RCPT: if (isTransit) result = false; break; case NotificationClass.VISIT: case NotificationClass.TRANSIT: case NotificationClass.STO: result = false; break; default: break; } return result; } #endregion #region ISublistContainer implementation public ISublistElement GetSublistElementWithIdentifier(string identifier) { foreach (DatabaseEntity entity in this.Elements) { ISublistElement sublistElement = entity as ISublistElement; if (sublistElement?.Identifier != null) { if (((ISublistElement)entity).Identifier.Equals(identifier)) return entity as ISublistElement; } } return null; } [Browsable(false)] [JsonIgnore] public int NumberOfExcelRows { get { switch (this.MessageNotificationClass) { case NotificationClass.BKRA: return 5; case NotificationClass.BKRD: return 5; case NotificationClass.LADG: return 36; case NotificationClass.CREWA: return 40; case NotificationClass.CREWD: return 40; case NotificationClass.PASA: return 40; case NotificationClass.PASD: return 40; case NotificationClass.TOWA: return 5; case NotificationClass.TOWD: return 5; case NotificationClass.STO: return 10; case NotificationClass.WAS_RCPT: return 5; default: return 0; } } } public void SaveElements() { if (CanDoBulkSave()) { this.BulkSaveElements(); } else { foreach (DatabaseEntity dbEntity in this.Elements) { DBManager.Instance.Save(dbEntity); if (dbEntity is ISublistContainer sublistContainer) { sublistContainer.SaveElements(); } } } } public void DeleteElements() { foreach (MessageError me in ErrorList) DBManager.Instance.Delete(me); foreach (MessageViolation mv in ViolationList) DBManager.Instance.Delete(mv); foreach (SystemError se in SystemErrorList) DBManager.Instance.Delete(se); foreach (DatabaseEntity dbEntity in this.Elements) { if (dbEntity is ISublistContainer sublistContainer) { (sublistContainer).DeleteElements(); } DBManager.Instance.Delete(dbEntity); } this.Elements.Clear(); } #endregion #region IMessageParagraph implementation public override string Title { get { if (this.Elements.Count > 0) { return this.Elements[0].Title; } else { return MessageNotificationClassDisplay; } } } public override string Subtitle { get { if (this.Elements.Count > 0) return this.Elements[0].Subtitle; else return string.Empty; } } public override List> MessageText { get { switch (this.MessageNotificationClass) { case NotificationClass.VISIT: case NotificationClass.TRANSIT: return base.MessageText; case NotificationClass.ATA: case NotificationClass.ATD: case NotificationClass.BPOL: case NotificationClass.HAZA: case NotificationClass.HAZD: case NotificationClass.INFO: case NotificationClass.MDH: case NotificationClass.NAME: case NotificationClass.NOA_NOD: case NotificationClass.POBA: case NotificationClass.POBD: case NotificationClass.PRE72H: case NotificationClass.SEC: case NotificationClass.STAT: case NotificationClass.AGNT: case NotificationClass.TIEFA: case NotificationClass.TIEFD: case NotificationClass.WAS: if (this.Elements.Count > 0) { return this.Elements[0].MessageText; } else { return null; } default: return null; } } } public override bool ShowChildrenAsTable { get { switch (this.MessageNotificationClass) { case NotificationClass.CREWA: case NotificationClass.PASA: return true; default: return false; } } } public override List ChildParagraphs { get { switch (this.MessageNotificationClass) { case NotificationClass.VISIT: case NotificationClass.TRANSIT: return null; case NotificationClass.ATA: case NotificationClass.ATD: case NotificationClass.BPOL: case NotificationClass.HAZA: case NotificationClass.HAZD: case NotificationClass.INFO: case NotificationClass.MDH: case NotificationClass.NAME: case NotificationClass.NOA_NOD: case NotificationClass.POBA: case NotificationClass.POBD: case NotificationClass.PRE72H: case NotificationClass.SEC: case NotificationClass.STAT: case NotificationClass.AGNT: case NotificationClass.TIEFA: case NotificationClass.TIEFD: case NotificationClass.WAS: if (this.Elements.Count > 0) { return this.Elements[0].ChildParagraphs; } else { return null; } default: List result = new List(); foreach (DatabaseEntity element in this.Elements) result.Add(element); return result; } } } #endregion #region IComparable implementation /// /// Sort messages by notification class /// public int CompareTo(Message other) { return this.MessageNotificationClass.CompareTo(other.MessageNotificationClass); } #endregion #region IClonable implementation public override object Clone() { // hier gibt es kein Memberwise Clone, weil die meisten Felder zurück gesetzt werden Message root = new Message(); root.MessageNotificationClass = this.MessageNotificationClass; root.InternalStatus = BSMDStatus.PREPARE; foreach (DatabaseEntity databaseEntity in this.Elements) { DatabaseEntity clonedElement = databaseEntity.Clone() as DatabaseEntity; clonedElement.MessageHeader = root; root.Elements.Add(clonedElement); } return root; } #endregion #region private methods private bool IsFlagSet(MessageFlags flag) { return (this.Flags & (int)flag) != 0; } private void SetFlag(bool value, MessageFlags flag) { if (value) this.Flags |= (int)flag; else this.Flags &= (int)~flag; } /// /// Bulk save is actually bulk insert and can only be done for certain /// message classes where bulk save is implemented /// private bool CanDoBulkSave() { if(this.MessageNotificationClass == NotificationClass.CREWA || this.MessageNotificationClass == NotificationClass.CREWD || this.MessageNotificationClass == NotificationClass.PASA || this.MessageNotificationClass == NotificationClass.PASD) { foreach (DatabaseEntity subEntity in this.Elements) if (!subEntity.IsNew) return false; return true; } return false; } private void BulkSaveElements() { if (this.Elements.Count == 0) return; // NOP if(this.Elements[0] is IBulkSaver ibs) { DataTable dt = ibs.PrepareBulkInsert(new List(this.Elements)); DBManager.Instance.PerformBulkInsert(dt); } else { throw new InvalidOperationException("bulk save called on classes that do not support it"); } } #endregion } }