|
|
|
|
@ -448,18 +448,6 @@ namespace Gremlin.GremlinData.DBClasses
|
|
|
|
|
//}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//public static bool ImportFromCSV<T>(T type, string filepath = "", string separator = ";", bool dataHasHeading = true)
|
|
|
|
|
//{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// return type switch
|
|
|
|
|
// {
|
|
|
|
|
// Account => ImportAccountsFromCSV(filepath, separator, dataHasHeading),
|
|
|
|
|
// Contact => ImportContactsFromCSV(filepath, separator, dataHasHeading),
|
|
|
|
|
// _ => default,
|
|
|
|
|
// };
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
public static bool ImportContactsFromCSV(string filepath = "", string separator = ";", bool dataHasHeading = true)
|
|
|
|
|
{
|
|
|
|
|
//Pfad abfragen über Dtei-Öffnen-Dialog:
|
|
|
|
|
@ -767,267 +755,6 @@ namespace Gremlin.GremlinData.DBClasses
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static bool GenericImporter(string filepath = "")//, string separator = "|")
|
|
|
|
|
//Ein (möglichst) generischer Importer
|
|
|
|
|
//1. Dateipfad erfassen
|
|
|
|
|
//2. Column <-> Property Mapping
|
|
|
|
|
//3. Typ der zu importierenden Daten herausfinden
|
|
|
|
|
//4. Daten einlesen, konvertieren, validieren, Metadaten setzen und alles in Liste(n) speichern
|
|
|
|
|
//5. Datenliste(n) in DB speichern
|
|
|
|
|
{
|
|
|
|
|
if (filepath == "") filepath = FileHelper.GetFilepathFromUser();
|
|
|
|
|
if (filepath == "") return false;
|
|
|
|
|
|
|
|
|
|
using (TextFieldParser csvParser = new(filepath, FileHelper.GetEncoding(filepath)))
|
|
|
|
|
{
|
|
|
|
|
//Parser configuration:
|
|
|
|
|
//csvParser.Delimiters = new string[] { separator };
|
|
|
|
|
csvParser.CommentTokens = new string[] { "#" };
|
|
|
|
|
csvParser.HasFieldsEnclosedInQuotes = true;
|
|
|
|
|
|
|
|
|
|
//dynamische Spaltenzuordnung in Dictonary speichern
|
|
|
|
|
Dictionary<string, string> ColumnToPropertyMapping = FileIO.ReadMappingTableFromFile();
|
|
|
|
|
Dictionary<string, int> columnNumberOf = new();
|
|
|
|
|
string[] fields = csvParser.ReadFields();
|
|
|
|
|
columnNumberOf = GenericColumnMapper(fields, ColumnToPropertyMapping);
|
|
|
|
|
|
|
|
|
|
//determine data type to be imported
|
|
|
|
|
string dataInFile = RecognizeData(columnNumberOf, FileIO.ReadDataIdentifierFromFile());
|
|
|
|
|
|
|
|
|
|
//prepare lists
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool dataIsValid;
|
|
|
|
|
|
|
|
|
|
while (!csvParser.EndOfData)
|
|
|
|
|
{
|
|
|
|
|
//read
|
|
|
|
|
//new data instance
|
|
|
|
|
//convert
|
|
|
|
|
//validate
|
|
|
|
|
//set metadata: SetMetadataForImport(IMetadata)
|
|
|
|
|
//add to list
|
|
|
|
|
|
|
|
|
|
fields = csvParser.ReadFields(); // Read current line fields, pointer moves to the next line.
|
|
|
|
|
if (fields[0] == "") break; // Am Ende hängt eine leere Zeile, die im Parser einen Fehler auslösen würde.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
using (GremlinContext db = new())
|
|
|
|
|
{
|
|
|
|
|
//add to context
|
|
|
|
|
//savechanges
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static string RecognizeData(Dictionary<string,int> mappingTable, List<DataIdentifier> dataIdentifier, bool MatchAllIdentifier = true)
|
|
|
|
|
{
|
|
|
|
|
List<string> AvailableTypes = new();
|
|
|
|
|
Dictionary<string, int> Score = new();
|
|
|
|
|
ValueTuple<string, int, bool> Scoring = new();
|
|
|
|
|
|
|
|
|
|
//build list of unique types
|
|
|
|
|
for (int i = 0; i < dataIdentifier.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
DataIdentifier qualifier = dataIdentifier[i];
|
|
|
|
|
if (AvailableTypes.Contains(qualifier.DataType) == false)
|
|
|
|
|
{
|
|
|
|
|
AvailableTypes.Add(qualifier.DataType);
|
|
|
|
|
Score.Add(qualifier.DataType, 0);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool _continue;
|
|
|
|
|
foreach (string datatype in AvailableTypes) //for each group of identifiers...
|
|
|
|
|
{
|
|
|
|
|
_continue = true;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
foreach (DataIdentifier qualifier in dataIdentifier) //...iterate through its corresponding identfiers...
|
|
|
|
|
{
|
|
|
|
|
if (qualifier.DataType == datatype
|
|
|
|
|
&& mappingTable.ContainsKey(qualifier.Identifier)) //...and check if identifier is in data set columns headings
|
|
|
|
|
{
|
|
|
|
|
int score = Score.GetValueOrDefault(datatype);
|
|
|
|
|
score++;
|
|
|
|
|
_ = Score.Remove(datatype);
|
|
|
|
|
Score.Add(datatype, score);
|
|
|
|
|
}
|
|
|
|
|
else //identifier nicht gefunden
|
|
|
|
|
{
|
|
|
|
|
if (MatchAllIdentifier)
|
|
|
|
|
{
|
|
|
|
|
//go to next datatype (outer foreach):
|
|
|
|
|
_continue = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (qualifier.DataType == datatype
|
|
|
|
|
&& qualifier.Identifier == "NumberOfColumns=2")
|
|
|
|
|
{
|
|
|
|
|
int score = Score.GetValueOrDefault(datatype);
|
|
|
|
|
score += 3;
|
|
|
|
|
Score.Remove(datatype);
|
|
|
|
|
Score.Add(datatype, score);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
while (_continue);
|
|
|
|
|
}
|
|
|
|
|
//return type with most hits:
|
|
|
|
|
return Score.Aggregate((x,y) => x.Value > y.Value ? x : y).Key;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static string RecognizeDataStatic(Dictionary<string, int> mappingDictionary)
|
|
|
|
|
{
|
|
|
|
|
//Logik zur Kategorisierung des Datensatzes:
|
|
|
|
|
//Alle verpflichtenden Angaben zu einer Klasse vorhanen?
|
|
|
|
|
//Alle vom Importer erwarteten Angaben vorhanden?
|
|
|
|
|
//Bei den Enums zusätzlich noch proüfem, dass nur zwei Spalten vorhanden sind, sonst könnten LSAG-Daten falsch identifiziert werden.
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
//Products
|
|
|
|
|
if (//required by DB:
|
|
|
|
|
mappingDictionary.ContainsKey("ProductNumber")
|
|
|
|
|
&& mappingDictionary.ContainsKey("ListPrice")
|
|
|
|
|
//required by importer:
|
|
|
|
|
&& mappingDictionary.ContainsKey("Weight")
|
|
|
|
|
//unique identifier:
|
|
|
|
|
&& mappingDictionary.ContainsKey("BreakRangeFrom")
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
return "Product";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//LSAG Contact List Tool List
|
|
|
|
|
if (//required by DB:
|
|
|
|
|
mappingDictionary.ContainsKey("SAPAccountNumber")
|
|
|
|
|
&& mappingDictionary.ContainsKey("SAPContactNumber")
|
|
|
|
|
&& mappingDictionary.ContainsKey("AccountTypeCode")
|
|
|
|
|
&& mappingDictionary.ContainsKey("SubMarketCode")
|
|
|
|
|
&& mappingDictionary.ContainsKey("LastName")
|
|
|
|
|
&& mappingDictionary.ContainsKey("AccountName")
|
|
|
|
|
//required by importer:
|
|
|
|
|
|
|
|
|
|
//unique identifier:
|
|
|
|
|
&& mappingDictionary.ContainsKey("MA_ProductInterests")
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
return "LSAG Contact List Tool List";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Accounts
|
|
|
|
|
if (//required by DB:
|
|
|
|
|
mappingDictionary.ContainsKey("AccountName")
|
|
|
|
|
&& mappingDictionary.ContainsKey("Street")
|
|
|
|
|
&& mappingDictionary.ContainsKey("ZIP")
|
|
|
|
|
&& mappingDictionary.ContainsKey("City")
|
|
|
|
|
&& mappingDictionary.ContainsKey("PhoneNumber")
|
|
|
|
|
&& mappingDictionary.ContainsKey("SAPAccountNumber")
|
|
|
|
|
&& mappingDictionary.ContainsKey("AccountCreatedInSAPOn")
|
|
|
|
|
&& mappingDictionary.ContainsKey("AccountTypeCode")
|
|
|
|
|
&& mappingDictionary.ContainsKey("SubMarketCode")
|
|
|
|
|
//required by importer:
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
return "Account";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Contacts
|
|
|
|
|
if (//required by DB:
|
|
|
|
|
mappingDictionary.ContainsKey("LastName")
|
|
|
|
|
&& mappingDictionary.ContainsKey("SAPContactNumber")
|
|
|
|
|
//required by importer:
|
|
|
|
|
&& mappingDictionary.ContainsKey("FirstName")
|
|
|
|
|
&& mappingDictionary.ContainsKey("Gender")
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
return "Contact";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Custom Description
|
|
|
|
|
if (//required by DB:
|
|
|
|
|
mappingDictionary.ContainsKey("Heading")
|
|
|
|
|
//required by importer:
|
|
|
|
|
&& mappingDictionary.ContainsKey("ProductNumber")
|
|
|
|
|
&& mappingDictionary.ContainsKey("OptionNumber")
|
|
|
|
|
&& mappingDictionary.ContainsKey("DescriptionText")
|
|
|
|
|
//unique identifier:
|
|
|
|
|
&& mappingDictionary.ContainsKey("CoverletterText")
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
return "CustomDescription";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//Pseudo-Enums AccountTypes, SubMarkets, ProductLines for DB-initializing
|
|
|
|
|
if (mappingDictionary.Count == 2)
|
|
|
|
|
{
|
|
|
|
|
if (mappingDictionary.ContainsKey("AccountTypeCode")
|
|
|
|
|
&& mappingDictionary.ContainsKey("AccountTypeDescription")
|
|
|
|
|
&& mappingDictionary.Count == 2)
|
|
|
|
|
{
|
|
|
|
|
return "AccountType";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mappingDictionary.ContainsKey("SubMarketCode")
|
|
|
|
|
&& mappingDictionary.ContainsKey("SubMarketDescription")
|
|
|
|
|
&& mappingDictionary.Count == 2)
|
|
|
|
|
{
|
|
|
|
|
return "SubMarket";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mappingDictionary.ContainsKey("ProductLineCode")
|
|
|
|
|
&& mappingDictionary.ContainsKey("ProductLineDescription")
|
|
|
|
|
&& mappingDictionary.Count == 2)
|
|
|
|
|
{
|
|
|
|
|
return "ProductLine";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return "No entity type unambigiously identified!";
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static IMetadata SetMetadataForImport(IMetadata entity,string datamodifiedby = "", string dataversioncomment = "", [CallerMemberName] string callername ="")
|
|
|
|
|
{
|
|
|
|
|
entity.DataCreationDate = DateTime.Now;
|
|
|
|
|
entity.DataModificationDate = DateTime.Now;
|
|
|
|
|
entity.DataModificationByUser = datamodifiedby == "" ? callername : datamodifiedby;
|
|
|
|
|
entity.DataStatus = Status.Active.ToString();
|
|
|
|
|
entity.DataValidFrom = DateTime.Now;
|
|
|
|
|
entity.DataValidUntil = FarInTheFuture;
|
|
|
|
|
entity.DataVersionNumber++;
|
|
|
|
|
entity.DataVersionComment = dataversioncomment;
|
|
|
|
|
|
|
|
|
|
return entity;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Dictionary<string, int> GenericColumnMapper(string[] headings, Dictionary<string, string> mappingTable)
|
|
|
|
|
{
|
|
|
|
|
Dictionary<string, int> result = new();
|
|
|
|
|
for (int i = 0; i < headings.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
string heading = headings[i].ToLower(CultureInfo.CurrentCulture)
|
|
|
|
|
.Trim()
|
|
|
|
|
.Replace(" ", "")
|
|
|
|
|
.Replace("-", "")
|
|
|
|
|
.Replace("_", "")
|
|
|
|
|
.Replace(".", "")
|
|
|
|
|
.Replace(":", "");
|
|
|
|
|
|
|
|
|
|
if (mappingTable.TryGetValue(heading, out string value))
|
|
|
|
|
{
|
|
|
|
|
result.Add(value, i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static bool ImportLSAGContactListToolData(string filepath = "", string separator = ";")
|
|
|
|
|
///Importiert Accounts und Contacts aus CSV in die DB
|
|
|
|
|
|
|
|
|
|
|