git_bsmd/bsmd.database/ValueMapping.cs

272 lines
8.4 KiB
C#

// Copyright (c) 2023-present schick Informatik
// Description: Container class for self-learning, volatile information that
// is added by parsing Excel sheets. Here common wrong/misspelled data fields
// are mapped to valid ones.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.SqlClient;
using System.Threading.Tasks;
namespace bsmd.database
{
public class ValueMapping : DatabaseEntityAsync, INotifyPropertyChanged
{
#region Construction
public ValueMapping()
{
this.tablename = "[dbo].[ValueMapping]";
}
#endregion
#region enums
public enum MappingType
{
COUNTRY,
GENDER,
DOCUMENT_TYPE,
LOCODE
}
#endregion
#region Fields
private static Dictionary<MappingType, Dictionary<string, ValueMapping>> _dicts;
private static Dictionary<MappingType, List<string>> _invalidKeys;
private string _key, _value, _valueText;
#endregion
#region Properties
public event PropertyChangedEventHandler PropertyChanged;
public static Dictionary<MappingType, Dictionary<string, ValueMapping>> Dicts
{
get
{
if (_dicts == null)
{
_dicts = new Dictionary<MappingType, Dictionary<string, ValueMapping>>();
foreach (MappingType type in Enum.GetValues(typeof(MappingType)))
_dicts[type] = new Dictionary<string, ValueMapping>();
}
return _dicts;
}
}
public static Dictionary<MappingType, List<string>> InvalidKeys
{
get
{
if (_invalidKeys == null)
{
_invalidKeys = new Dictionary<MappingType, List<string>>();
// get the keys initialized that cannot be assigned
foreach (MappingType type in Enum.GetValues(typeof(MappingType)))
_invalidKeys[type] = new List<string>();
}
return _invalidKeys;
}
}
public MappingType EntryType { get; private set; }
public string Key
{
get { return _key; }
set
{
if (!value.Equals(_key)) this.IsDirty = true;
this._key = value;
this.OnPropertyChanged("Key");
}
}
public string Value
{
get { return _value; }
set
{
if (!value.Equals(_value)) this.IsDirty = true;
_value = value;
OnPropertyChanged("Value");
}
}
public string ValueText
{
get { return _valueText; }
set
{
this._valueText = value;
this.OnPropertyChanged("ValueText");
}
}
public DateTime? Created { get; private set; }
public DateTime? Changed { get; private set; }
#endregion
#region public funcs
/// <summary>
/// creates and saves a new entry and adds it to the internal dictionaries
/// </summary>
/// <returns>true if entry was actually created, false if already present</returns>
public static async Task<bool> Create(MappingType type, string key, string value)
{
if (!Dicts[type].ContainsKey(key))
{
ValueMapping vm = new ValueMapping()
{
EntryType = type,
Key = key,
Value = value
};
if (value.Equals("*"))
InvalidKeys[type].Add(key);
else
Dicts[type][key] = vm;
return await DBManagerAsync.SaveAsync(vm) == 1;
}
return false;
}
/// <summary>
/// Create through manual editing in global scope
/// </summary>
public static ValueMapping Create(MappingType type)
{
ValueMapping vm = new ValueMapping()
{
EntryType = type
};
return vm;
}
/// <summary>
/// deletes an entry and removes it from the database
/// </summary>
/// <returns>true if successful, false if value was not found</returns>
public static async Task<bool> Delete(MappingType type, string key)
{
if (!Dicts.ContainsKey(type)) return false;
if (!Dicts[type].ContainsKey(key)) return false;
ValueMapping vm = Dicts[type][key];
Dicts[type].Remove(key);
return await DBManagerAsync.DeleteAsync(vm) == 1;
}
/// <summary>
/// updates an existing value and saves it
/// </summary>
/// <returns>true if successful</returns>
public async Task<bool> Update(string newValue)
{
this.Value = newValue;
return await DBManagerAsync.SaveAsync(this) == 1;
}
/// <summary>
/// (re-)loads all value mapping dictionaries
/// </summary>
public static async void LoadDicts()
{
foreach(MappingType type in Enum.GetValues(typeof(MappingType)))
{
Dicts[type].Clear();
List<ValueMapping> mappings = await DBManagerAsync.LoadValuesForType(type);
foreach (ValueMapping mapping in mappings)
{
if (mapping.Value.Equals("*"))
InvalidKeys[type].Add(mapping.Key);
else
Dicts[type][mapping.Key] = mapping;
}
}
}
#endregion
#region DatabaseEntity implementation
public override void PrepareSave(System.Data.IDbCommand cmd)
{
SqlCommand scmd = cmd as SqlCommand;
scmd.Parameters.AddWithValue("@TYPE", this.EntryType);
scmd.Parameters.AddWithNullableValue("@KEY", this.Key);
scmd.Parameters.AddWithNullableValue("@VALUE", this.Value);
if(this.IsNew)
{
this.CreateId();
scmd.Parameters.AddWithValue("@ID", this.Id);
scmd.CommandText = $"INSERT INTO {Tablename} (Id, EntryType, MappingKey, MappingValue) VALUES (@ID, @TYPE, @KEY, @VALUE)";
}
else
{
scmd.Parameters.AddWithValue("@ID", this.Id);
scmd.CommandText = $"UPDATE {Tablename} SET EntryType = @TYPE, MappingKey = @KEY, MappingValue = @VALUE WHERE Id = @ID";
}
}
public override void PrepareLoadCommand(System.Data.IDbCommand cmd, Message.LoadFilter filter, params object[] criteria)
{
string query = $"SELECT Id, EntryType, MappingKey, MappingValue, Created, Changed FROM {Tablename}";
switch (filter)
{
case Message.LoadFilter.BY_TYPE:
query += " WHERE EntryType = @TYPE";
((SqlCommand)cmd).Parameters.AddWithValue("@TYPE", criteria[0]);
break;
default:
break;
}
query += " ORDER BY MappingKey";
cmd.CommandText = query;
}
protected override DatabaseEntityAsync ReadRowFromReader(System.Data.IDataReader reader)
{
ValueMapping vm = null;
if (reader != null)
{
vm = new ValueMapping();
vm.id = reader.GetGuid(0);
if (!reader.IsDBNull(1)) vm.EntryType = (ValueMapping.MappingType)reader.GetByte(1);
if (!reader.IsDBNull(2)) vm._key = reader.GetString(2);
if (!reader.IsDBNull(3)) vm._value = reader.GetString(3);
if (!reader.IsDBNull(4)) vm.Created = reader.GetDateTime(4);
if (!reader.IsDBNull(5)) vm.Changed = reader.GetDateTime(5);
}
return vm;
}
#endregion
#region protected methods
protected void OnPropertyChanged(string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
#endregion
}
}