using System; using System.Collections.Generic; using System.Text; using System.Net; using System.IO; using System.Globalization; using System.Reflection; using System.Diagnostics; using System.Runtime.InteropServices; using System.ComponentModel; using System.Configuration; using System.Data; using System.Data.SQLite; using System.Runtime.Serialization.Formatters.Binary; using System.Xml; using System.Xml.Serialization; using Newtonsoft.Json; namespace System.Data.SQLite { /// /// Holds basic functionaltity /// [System.ComponentModel.DesignerCategory("")] [Serializable] public class SQLiteEntry { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // be sure to have a copy of these static members in each derived class !! // individual static SQL strings per class will be created on first use // add a "new" statement on each derived class to confirm hiding of the base class members // update the tbale name to the table name according to the class // update the PrimaryKeys collection according to the class, crreate an empty list if no primary key ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// [JsonIgnore] public static readonly string TableName = "Table"; [JsonIgnore] public static List PrimaryKeys = SQLiteSQLFactory.FillPrimaryKeys(MethodBase.GetCurrentMethod().DeclaringType, new List()); [JsonIgnore] public static readonly string SQLCreateTable = SQLiteSQLFactory.SQLCreateTable(MethodBase.GetCurrentMethod().DeclaringType); [JsonIgnore] public static readonly string SQLExists = SQLiteSQLFactory.SQLExists(MethodBase.GetCurrentMethod().DeclaringType); [JsonIgnore] public static readonly string SQLFind = SQLiteSQLFactory.SQLFind(MethodBase.GetCurrentMethod().DeclaringType); [JsonIgnore] public static readonly string SQLFindLastUpdated = SQLiteSQLFactory.SQLFindLastUpdated(MethodBase.GetCurrentMethod().DeclaringType); [JsonIgnore] public static readonly string SQLInsert = SQLiteSQLFactory.SQLInsert(MethodBase.GetCurrentMethod().DeclaringType); [JsonIgnore] public static readonly string SQLUpdate = SQLiteSQLFactory.SQLUpdate(MethodBase.GetCurrentMethod().DeclaringType); ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public DateTime LastUpdated { get; set; } public SQLiteEntry() { LastUpdated = DateTime.MinValue.ToUniversalTime(); } public SQLiteEntry(DataRow row) : this() { FillFromDataRow(row); } public SQLiteEntry(IDataRecord record) : this() { FillFromDataRecord(record); } /// /// Creates an object of type T from a DataRow. Tries to fill all property values from the according columns. /// /// The DataRow to create object from. protected void FillFromDataRow(DataRow row) { try { int i = 0; PropertyInfo[] properties = this.GetType().GetProperties(); foreach (PropertyInfo p in properties) { // skip read only properties if (!p.CanWrite) continue; // get column index int index = row.Table.Columns.IndexOf(p.Name); // NASTY!!! Linux/Mono hack: check if column name is present in table // --> use incremental index instead which should do the same job basically because columns are arranged the same way as type's properties // found, that Windows arranges the properties not always in the same manner if (index < 0) index = i; // Console.WriteLine("[" + T.Name + ".FillFromRow] DataColumn not found: " + p.Name); if (p.PropertyType == typeof(string)) p.SetValue(this, (row[index].GetType() != typeof(DBNull)) ? row[index] : null, null); else if ((p.PropertyType == typeof(float)) || (p.PropertyType == typeof(double))) p.SetValue(this, (row[index].GetType() !=typeof(DBNull)) ? row[index] : null, null); else if (p.PropertyType == typeof(int)) p.SetValue(this, (row[index].GetType() != typeof(DBNull)) ? row[index] : null, null); else if (p.PropertyType == typeof(DateTime)) { if ((row[index].GetType() == typeof(int)) || (row[index].GetType() == typeof(long))) p.SetValue(this, UNIXTimeToDateTime(System.Convert.ToInt32(row[index])), null); else if (row[index].GetType() == typeof(string)) p.SetValue(this, DateTime.ParseExact(row[index].ToString(), "yyyy-MM-dd HH:mm:ssZ", CultureInfo.InvariantCulture).ToUniversalTime(), null); else p.SetValue(this, row[index], null); } else if (p.PropertyType.BaseType == typeof(Enum)) p.SetValue(this, System.Convert.ToInt32(row[index]), null); else p.SetValue(this, ByteArrayToObject((byte[])row[index]), null); i++; } } catch (Exception ex) { Console.WriteLine(ex.ToString()); } } /// /// Creates an object of type T from a IDataRecord interface (e.g. SQLiteDataReader). Tries to fill all property values from the according record fields. /// /// The IDataRecord to create object from. protected void FillFromDataRecord(IDataRecord record) { try { int i = 0; PropertyInfo[] properties = this.GetType().GetProperties(); foreach (PropertyInfo p in properties) { // skip read only properties if (!p.CanWrite) continue; // get column index int index = record.GetOrdinal(p.Name); // NASTY!!! Linux/Mono hack: check if column name is present in table // --> use incremental index instead which should do the same job basically because columns are arranged the same way as type's properties // found, that Windows arranges the properties not always in the same manner if (index < 0) index = i; // Console.WriteLine("[" + T.Name + ".FillFromRow] DataColumn not found: " + p.Name); if (p.PropertyType == typeof(string)) p.SetValue(this, (record[index].GetType() != typeof (DBNull)) ? record[index] : null, null); else if ((p.PropertyType == typeof(float)) || (p.PropertyType == typeof(double))) p.SetValue(this, (record[index].GetType() != typeof(DBNull)) ? record[index] : null, null); else if (p.PropertyType == typeof(int)) p.SetValue(this, (record[index].GetType() != typeof(DBNull)) ? record[index] : null, null); else if (p.PropertyType == typeof(DateTime)) { if ((record[index].GetType() == typeof(int)) || (record[index].GetType() == typeof(long))) p.SetValue(this, UNIXTimeToDateTime(System.Convert.ToInt32(record[index])), null); else if (record[index].GetType() == typeof(string)) p.SetValue(this, DateTime.ParseExact(record[index].ToString(), "yyyy-MM-dd HH:mm:ssZ", CultureInfo.InvariantCulture).ToUniversalTime(), null); else p.SetValue(this, record[index], null); } else if (p.PropertyType.BaseType == typeof(Enum)) p.SetValue(this, System.Convert.ToInt32(record[index]), null); else p.SetValue(this, ByteArrayToObject((byte[])record[index]), null); i++; } } catch (Exception ex) { Console.WriteLine(ex.ToString()); } } /// /// Converts object to JSON string /// /// JSON string representing the object. public string ToJSON() { JsonSerializerSettings settings = new JsonSerializerSettings(); settings.DateTimeZoneHandling = DateTimeZoneHandling.Utc; settings.FloatFormatHandling = FloatFormatHandling.String; settings.Formatting = Newtonsoft.Json.Formatting.Indented; settings.Culture = CultureInfo.InvariantCulture; string json = JsonConvert.SerializeObject(this, settings); return json; } /// /// Creates an object of .NET type from a JSON string. /// /// The JSON string. /// Object of .NET type created from JSON string public static T FromJSON(string json) { JsonSerializerSettings settings = new JsonSerializerSettings(); settings.DateTimeZoneHandling = DateTimeZoneHandling.Utc; settings.FloatFormatHandling = FloatFormatHandling.String; settings.Formatting = Newtonsoft.Json.Formatting.Indented; settings.Culture = CultureInfo.InvariantCulture; return JsonConvert.DeserializeObject(json, settings); } /// /// Creates an object of .NET type from a JSON file. /// /// The JSON file. /// Object of .NET type created from JSON file. /// public static T FromJSONFile(string filename) { string json = ""; using (StreamReader sr = new StreamReader(File.OpenRead(filename))) { json = sr.ReadToEnd(); } return FromJSON(json); } /// Converts an object to an array of bytes. /// /// The object. /// Array of bytes representing the object. private static byte[] ObjectToByteArray(Object obj) { BinaryFormatter bf = new BinaryFormatter(); using (var ms = new MemoryStream()) { bf.Serialize(ms, obj); return ms.ToArray(); } } /// /// Converts an array of bytes into an object. /// /// The array of bytes representing the object. /// The object. private static Object ByteArrayToObject(byte[] arr) { using (var memStream = new MemoryStream()) { var binForm = new BinaryFormatter(); memStream.Write(arr, 0, arr.Length); memStream.Seek(0, SeekOrigin.Begin); var obj = binForm.Deserialize(memStream); return obj; } } /// /// Converts a DateTime into UNIX Epoch time /// Handles MinValue and MaxValue correctly /// /// The DateTime to be converted. /// The UNIX Epoch time. Fractional seconds will be lost. public static int DateTimeToUNIXTime(DateTime dt) { if (dt == DateTime.MinValue) return int.MinValue; else if (dt == DateTime.MaxValue) return int.MaxValue; return (int)(dt.Subtract(new DateTime(1970, 1, 1))).TotalSeconds; } /// /// Converts a UNIX Epoch time into DateTime /// Handles MinValue and MaxValue correctly /// /// The UNIX Epoch time to be converted. /// The DateTime (in UTC). public static DateTime UNIXTimeToDateTime(int ut) { if (ut == int.MinValue) return DateTime.MinValue; else if (ut == int.MaxValue) return DateTime.MaxValue; DateTime dt = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); return dt.AddSeconds(ut); } public SQLiteParameter AsString(string name) { object obj = this.GetType().GetProperty(name).GetValue(this, null); SQLiteParameter par = new SQLiteParameter(DbType.String, obj); par.ParameterName = "@" + name; return par; } public SQLiteParameter AsInt32(string name) { object obj = this.GetType().GetProperty(name).GetValue(this, null); SQLiteParameter par = new SQLiteParameter(DbType.Int32, obj); par.ParameterName = "@" + name; return par; } public SQLiteParameter AsSingle(string name) { object obj = System.Convert.ToSingle(this.GetType().GetProperty(name).GetValue(this, null)); SQLiteParameter par = new SQLiteParameter(DbType.Single, obj); par.ParameterName = "@" + name; return par; } public SQLiteParameter AsDouble(string name) { object obj = System.Convert.ToDouble(this.GetType().GetProperty(name).GetValue(this, null)); SQLiteParameter par = new SQLiteParameter(DbType.Double, obj); par.ParameterName = "@" + name; return par; } public SQLiteParameter AsUNIXTime(string name) { object obj = this.GetType().GetProperty(name).GetValue(this, null); int time = SQLiteEntry.DateTimeToUNIXTime((DateTime)obj); // don't forget to cast integer back to object, otherwise we will get a wrong function call SQLiteParameter(DBType type, int Parametersize)! SQLiteParameter par = new SQLiteParameter(DbType.Int32,(object)time); par.ParameterName = "@" + name; return par; } public SQLiteParameter AsBinary (string name) { object obj = this.GetType().GetProperty(name).GetValue(this, null); byte[] b = ObjectToByteArray(obj); SQLiteParameter par = new SQLiteParameter(name, DbType.Binary); par.Size = b.Length; par.Value = b; return par; } } }