git_bsmd/nsw/Source/bsmd.database/DatabaseEntity.cs

286 lines
10 KiB
C#

//
// Class: IDatabaseEntity
// Current CLR: 4.0.30319.34209
// System: Microsoft Visual Studio 10.0
// Author: dani
// Created: 3/2/2015 9:08:47 PM
//
// Copyright (c) 2015 Informatikbüro Daniel Schick. All rights reserved.
using System;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using System.Text.RegularExpressions;
namespace bsmd.database
{
public abstract class DatabaseEntity : IMessageParagraph, IEquatable<DatabaseEntity>
{
protected Guid? id;
protected string tablename;
private Guid instance_id = Guid.NewGuid(); // Comparison id in case entity has not been saved
#region enum ValidationBlock
public enum ValidationBlock
{
BLOCK1,
BLOCK2
}
#endregion
#region Properties
/// <summary>
/// Nachrichtentyp der abgeleiteten Meldeklassen
/// </summary>
public Message.NotificationClass MessageNotificationClass { get; set; }
public string MessageNotificationClassDisplay
{
get
{
return this.MessageNotificationClass.ToString();
}
}
/// <summary>
/// Referenz zur eigentlichen Schiffankunft
/// </summary>
public MessageCore MessageCore { get; set; }
/// <summary>
/// gemeinschaftliche Daten
/// </summary>
public Message MessageHeader { get; set; }
/// <summary>
/// SQL Table name to construct queries
/// </summary>
public virtual string Tablename { get { return this.tablename; } }
/// <summary>
/// primary key
/// </summary>
public Guid? Id { get { return this.id; } }
/// <summary>
/// IsNew Flag
/// </summary>
public bool IsNew { get { return !this.id.HasValue; } }
#endregion
#region public funcs
/// <summary>
/// when it's time (during save), create id
/// </summary>
public void CreateId() { this.id = Guid.NewGuid(); }
public abstract void PrepareSave(IDbCommand cmd);
public virtual void PrepareDelete(IDbCommand cmd)
{
SqlCommand scmd = cmd as SqlCommand;
scmd.CommandText = string.Format("DELETE FROM {0} WHERE Id = @ID", Tablename);
scmd.Parameters.AddWithValue("@ID", this.Id);
}
/// <summary>
/// Ergebnismenge begrenzen: NULL = kein Limit. Abgeleitete Klassen *können* diesen Parameter berücksichtigen
/// </summary>
public int? ResultLimit { get; set; }
public abstract void PrepareLoadCommand(IDbCommand cmd, Message.LoadFilter filter, params object[] criteria);
public abstract List<DatabaseEntity> LoadList(IDataReader reader);
public virtual void PrepareCountCmd(IDbCommand cmd, Message.LoadFilter filter, params object[] criteria)
{
SqlCommand scmd = cmd as SqlCommand;
scmd.CommandText = string.Format("SELECT COUNT(*) FROM {0}", Tablename);
}
/// <summary>
/// Überprüft eingegangene Meldeklassen auf Fehlerkonditionen
/// </summary>
/// <param name="errors"></param>
/// <param name="violations"></param>
public virtual void Validate(List<MessageError> errors, List<MessageViolation> violations)
{
errors = new List<MessageError>();
violations = new List<MessageViolation>();
}
/// <summary>
/// Diese Methode sollte eigentlich nie einen Effekt haben und dient nur dazu, dass keine Situation
/// auftreten kann in der ein Insert/Update an fehlender Datenvalidierung kracht
/// </summary>
/// <param name="truncated"></param>
public virtual void TruncateFields(List<string> truncated)
{
List<PropertyInfo> props = new List<PropertyInfo>();
// add flagged properties to check list
props.AddRange(this.GetType().GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(MaxLengthAttribute))));
foreach (PropertyInfo property in props)
{
object propValue = property.GetValue(this, null);
string value = (propValue == null) ? string.Empty : propValue.ToString();
MaxLengthAttribute maxLengthAttribute = Attribute.GetCustomAttribute(property, typeof(MaxLengthAttribute))
as MaxLengthAttribute;
if(value.Length > maxLengthAttribute.MaxLength) // truncate situation
{
string maxLengthValue = value.Substring(0, maxLengthAttribute.MaxLength);
truncated.Add(string.Format("[{0} ({1})]: {2}", property.Name, maxLengthAttribute.MaxLength, value));
property.SetValue(this, maxLengthValue);
}
}
}
/// <summary>
/// Kann überschrieben werden, wenn abhängig von den Daten (einem Flag) andere Regeln gelten (Bsp. wenn schon eine
/// MDH Meldung abgegeben wurde)
/// </summary>
/// <returns></returns>
public virtual ValidationBlock GetValidationBlock()
{
return ValidationBlock.BLOCK1;
}
#endregion
#region public static funcs
/// <summary>
/// Wenn Positionen manuell (ENI-2) angelegt werden, kann mit dieser Funktion der neue "Identifier"
/// festgelegt werden
/// </summary>
/// <param name="sublist">Vorhandene Position</param>
/// <returns>Name des neuen Identifiers, der so nicht in der Liste vorkommt</returns>
public static string GetNewIdentifier(IEnumerable<DatabaseEntity> sublist)
{
int maxVal = -1;
string maxString = null;
// das sieht riskanter aus als es ist, diese Funktion wird aber nur für Elemente angewendet, die
// ISublistElement implementieren
foreach(ISublistElement element in sublist)
{
if (element.Identifier.IsNullOrEmpty()) continue;
int elementIdent;
// TODO: Beim Parsen auch Text- und allerlei bunte Erweiterungen tolerieren
// (z.B. MARPOL-000001)
Regex re = new Regex(@"\d+");
Match m = re.Match(element.Identifier);
if (m.Success)
{
elementIdent = Int32.Parse(m.Value);
if (elementIdent > maxVal)
{
maxVal = elementIdent;
maxString = element.Identifier.Replace(m.Value, (maxVal + 1).ToString());
}
}
}
if (maxVal == -1) return 1.ToString();
return maxString;
}
#endregion
#region IEquatable<T> implementation
public bool Equals(DatabaseEntity other)
{
if (other == null) return false;
if (this.Id.HasValue && other.Id.HasValue && (this.Id.Value != Guid.Empty) && (other.Id.Value != Guid.Empty))
return this.Id == other.Id;
return this.GetHashCode() == other.GetHashCode();
}
public override bool Equals(object obj)
{
return this.Equals(obj as DatabaseEntity);
}
public override int GetHashCode()
{
if (!this.Id.HasValue || this.Id.Value == Guid.Empty)
return this.instance_id.GetHashCode();
return this.Id.GetHashCode();
}
#endregion
#region IMessageParagraph implementation
public virtual string Title
{
get
{
string name = this.GetType().Name;
return name;
}
}
public virtual string Subtitle
{
get { return string.Empty; }
}
public virtual bool ShowChildrenAsTable
{
get { return false; }
}
/// <summary>
/// must be overridden if it must make sense
/// </summary>
public virtual List<KeyValuePair<string, string>> MessageText
{
get {
List<KeyValuePair<string, string>> result = new List<KeyValuePair<string, string>>();
Type objType = this.GetType();
var props = objType.GetProperties().Where(
prop => Attribute.IsDefined(prop, typeof(ShowReportAttribute)));
foreach (PropertyInfo property in props)
{
bool isDouble = (property.PropertyType == typeof(Nullable<double>));
object propValue = property.GetValue(this, null);
string value = (propValue == null) ? string.Empty : (isDouble ? ((double) propValue).ToString("N2") : propValue.ToString());
string displayName = property.Name;
if(Attribute.IsDefined(property, typeof(ReportDisplayNameAttribute))) {
ReportDisplayNameAttribute reportDisplayNameAttribute = Attribute.GetCustomAttribute(property, typeof(ReportDisplayNameAttribute))
as ReportDisplayNameAttribute;
displayName = reportDisplayNameAttribute.DisplayName;
}
result.Add(new KeyValuePair<string, string>(displayName, value));
}
return result;
}
}
public virtual List<IMessageParagraph> ChildParagraphs { get { return null; } }
#endregion
}
}