using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; namespace InABox.Core { [Serializable] public class CoreRow : ICoreRow { #region Fields [NonSerialized] private static Dictionary _accessedcolumns = new Dictionary(); [NonSerialized] private Dictionary _columnindexes = new Dictionary(); #endregion #region Properties [DoNotSerialize] [field: NonSerialized] public CoreTable Table { get; private set; } public List Values { get; private set; } [DoNotSerialize] public int Index => Table.Rows.IndexOf(this); #endregion protected internal CoreRow(CoreTable owner) { Table = owner; Values = new List(); } public static CoreRow[] None { get { return new CoreRow[] { }; } } //private DynamicObject rowObject; public Dictionary ToDictionary(string[]? exclude = null) { var result = new Dictionary(); var columns = exclude == null ? Table.Columns : Table.Columns.Where(x => !exclude.Contains(x.ColumnName)); foreach (var column in columns) result[column.ColumnName] = this[column.ColumnName]; return result; } [DoNotSerialize] public object? this[string columnName] { get => //return this.RowObject.GetValue(columnName); Get(columnName); set => //this.RowObject.SetValue(columnName, value); Set(columnName, value); } /// /// Fill an object with the data from this row. /// /// /// If is , then the data in the row will override the data in , /// even if that column has previously been loaded (i.e., it is in ). /// /// The type of . /// The object to fill. /// Override any data which already exists in . public void FillObject(Type t, BaseObject obj, bool overrideExisting = false) { obj.SetObserving(false); if (!Table.Setters.TryGetValue("", out var setters)) { setters = new List?>(); Table.Setters[""] = setters; } var bFirst = !setters.Any(); for (var i = 0; i < Table.Columns.Count; i++) { var column = Table.Columns[i].ColumnName; var value = i < Values.Count ? Values[i] : CoreUtils.GetDefault(Table.Columns[i].DataType); try { if (obj.LoadedColumns.Add(column) || overrideExisting) { if (bFirst) { var prop = DatabaseSchema.Property(t, column); setters.Add(prop?.Setter()); } var setter = setters[i]; if (setter != null && value != null && !(value is System.DBNull)) setter.Invoke(obj, value); else CoreUtils.SetPropertyValue(obj, column, value); } } catch (Exception e) { Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace)); } } obj.CommitChanges(); obj.SetObserving(true); } /// /// Fill an object with the data from this row. /// /// /// If is , then the data in the row will override the data in , /// even if that column has previously been loaded (i.e., it is in ). /// /// The object to fill. /// Override any data which already exists in . public void FillObject(T obj, bool overrideExisting = false) where T : BaseObject { FillObject(typeof(T), obj, overrideExisting: overrideExisting); } public BaseObject ToObject(Type t) { var entity = (Activator.CreateInstance(t) as BaseObject)!; FillObject(t, entity, overrideExisting: true); return entity; } public T ToObject() where T : BaseObject, new() { return (ToObject(typeof(T)) as T)!; } public T Get(int col, bool usedefault = true) { if (col < 0 || col >= Values.Count) { if (usedefault) return CoreUtils.GetDefault(); throw new Exception(string.Format("Column [{0}] does not exist!", col)); } return Values[col] != null ? (T)CoreUtils.ChangeType(Values[col], typeof(T)) : CoreUtils.GetDefault(); } public T Get(string columnname, bool usedefault = true) { var col = GetColumn(columnname); if (col < 0 || col >= Values.Count) { if (usedefault) return CoreUtils.GetDefault(); throw new Exception(string.Format("Column [{0}] does not exist!", columnname)); } return Values[col] != null ? (T)CoreUtils.ChangeType(Values[col], typeof(T)) : CoreUtils.GetDefault(); } public TType Get(Expression> expression, bool usedefault = true) { var colname = GetColName(expression); //String colname = CoreUtils.GetFullPropertyName(expression, "."); return Get(colname, usedefault); } public void Set(Expression> expression, TType value) { var colname = GetColName(expression); //String colname = CoreUtils.GetFullPropertyName(expression, "."); Set(colname, value); } public void Set(int col, T value) { while (Values.Count <= col) Values.Add(Table.Columns[Values.Count].DataType.GetDefault()); Values[col] = value; } public void Set(string columnname, T value) { var col = GetColumn(columnname); if (col < 0) throw new Exception("Column not found: " + columnname); while (Values.Count <= col) Values.Add(Table.Columns[Values.Count].DataType.GetDefault()); Values[col] = value; //this.RowObject.SetValue(columnname, value); } public void LoadValues(IEnumerable values) { Values = values.ToList(); } public T ToObject(Expression> property) where TLink : IEntityLink where T : BaseObject, new() { var entity = new T(); entity.SetObserving(false); var prefix = CoreUtils.GetFullPropertyName(property, "."); if (!Table.Setters.TryGetValue(prefix, out var setters)) { setters = new List?>(); Table.Setters[prefix] = setters; } var bFirst = !setters.Any(); var cols = Table.Columns.Where(x => x.ColumnName.StartsWith(prefix + ".")).ToArray(); for (var i = 0; i < cols.Length; i++) { var column = cols[i].ColumnName; var prop = column.Substring((prefix + ".").Length); var value = this[column]; try { if (bFirst) { var p2 = DatabaseSchema.Property(typeof(T), prop); setters.Add(p2?.Setter()); } var setter = setters[i]; if (setter != null && value != null) setter.Invoke(entity, value); else CoreUtils.SetPropertyValue(entity, prop, value); } catch (Exception e) { Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace)); } } entity.CommitChanges(); entity.SetObserving(true); return entity; } private string GetColName(Expression> expression) { //int hash = expression.GetHashCode(); //if (_accessedcolumns.ContainsKey(hash)) // return _accessedcolumns[hash]; var colname = CoreUtils.GetFullPropertyName(expression, "."); //_accessedcolumns[hash] = colname; return colname; } private int GetColumn(string columnname) { if (_columnindexes.ContainsKey(columnname)) return _columnindexes[columnname]; for (var i = 0; i < Table.Columns.Count; i++) if (Table.Columns[i].ColumnName.Equals(columnname)) { _columnindexes[columnname] = i; return i; } _columnindexes[columnname] = -1; return -1; } } public static class CoreRowExtensions { public static IEnumerable ToObjects(this IEnumerable rows) where T : BaseObject, new() { return rows.Select(x => x.ToObject()); } } }