CoreRow.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. namespace InABox.Core
  6. {
  7. [Serializable]
  8. public class CoreRow : ICoreRow
  9. {
  10. #region Fields
  11. [NonSerialized]
  12. private static Dictionary<int, string> _accessedcolumns = new Dictionary<int, string>();
  13. [NonSerialized]
  14. private Dictionary<string, int> _columnindexes = new Dictionary<string, int>();
  15. #endregion
  16. #region Properties
  17. [DoNotSerialize]
  18. [field: NonSerialized]
  19. public CoreTable Table { get; private set; }
  20. public List<object?> Values { get; private set; }
  21. [DoNotSerialize]
  22. public int Index => Table.Rows.IndexOf(this);
  23. #endregion
  24. protected internal CoreRow(CoreTable owner)
  25. {
  26. Table = owner;
  27. Values = new List<object?>();
  28. }
  29. public static CoreRow[] None
  30. {
  31. get { return new CoreRow[] { }; }
  32. }
  33. //private DynamicObject rowObject;
  34. public Dictionary<string, object?> ToDictionary(string[]? exclude = null)
  35. {
  36. var result = new Dictionary<string, object?>();
  37. var columns = exclude == null
  38. ? Table.Columns
  39. : Table.Columns.Where(x => !exclude.Contains(x.ColumnName));
  40. foreach (var column in columns)
  41. result[column.ColumnName] = this[column.ColumnName];
  42. return result;
  43. }
  44. [DoNotSerialize]
  45. public object? this[string columnName]
  46. {
  47. get =>
  48. //return this.RowObject.GetValue<object>(columnName);
  49. Get<object>(columnName);
  50. set =>
  51. //this.RowObject.SetValue(columnName, value);
  52. Set(columnName, value);
  53. }
  54. /// <summary>
  55. /// Fill an object with the data from this row.
  56. /// </summary>
  57. /// <remarks>
  58. /// If <paramref name="overrideExisting"/> is <see langword="true"/>, then the data in the row will override the data in <paramref name="obj"/>,
  59. /// even if that column has previously been loaded (i.e., it is in <see cref="BaseObject.LoadedColumns"/>).
  60. /// </remarks>
  61. /// <param name="t">The type of <paramref name="obj"/>.</param>
  62. /// <param name="obj">The object to fill.</param>
  63. /// <param name="overrideExisting">Override any data which already exists in <paramref name="obj"/>.</param>
  64. public void FillObject(Type t, BaseObject obj, bool overrideExisting = false)
  65. {
  66. obj.SetObserving(false);
  67. if (!Table.Setters.TryGetValue("", out var setters))
  68. {
  69. setters = new List<Action<object, object>?>();
  70. Table.Setters[""] = setters;
  71. }
  72. var bFirst = !setters.Any();
  73. for (var i = 0; i < Table.Columns.Count; i++)
  74. {
  75. var column = Table.Columns[i].ColumnName;
  76. var value = this[column];
  77. try
  78. {
  79. if (obj.LoadedColumns.Add(column) || overrideExisting)
  80. {
  81. if (bFirst)
  82. {
  83. var prop = DatabaseSchema.Property(t, column);
  84. setters.Add(prop?.Setter());
  85. }
  86. var setter = setters[i];
  87. if (setter != null && value != null)
  88. setter.Invoke(obj, value);
  89. else
  90. CoreUtils.SetPropertyValue(obj, column, value);
  91. }
  92. }
  93. catch (Exception e)
  94. {
  95. Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
  96. }
  97. }
  98. obj.CommitChanges();
  99. obj.SetObserving(true);
  100. }
  101. /// <summary>
  102. /// Fill an object with the data from this row.
  103. /// </summary>
  104. /// <remarks>
  105. /// If <paramref name="overrideExisting"/> is <see langword="true"/>, then the data in the row will override the data in <paramref name="obj"/>,
  106. /// even if that column has previously been loaded (i.e., it is in <see cref="BaseObject.LoadedColumns"/>).
  107. /// </remarks>
  108. /// <param name="obj">The object to fill.</param>
  109. /// <param name="overrideExisting">Override any data which already exists in <paramref name="obj"/>.</param>
  110. public void FillObject<T>(T obj, bool overrideExisting = false) where T : BaseObject
  111. {
  112. FillObject(typeof(T), obj, overrideExisting: overrideExisting);
  113. }
  114. public BaseObject ToObject(Type t)
  115. {
  116. var entity = (Activator.CreateInstance(t) as BaseObject)!;
  117. FillObject(t, entity, overrideExisting: true);
  118. return entity;
  119. }
  120. public T ToObject<T>() where T : BaseObject, new()
  121. {
  122. return (ToObject(typeof(T)) as T)!;
  123. }
  124. public T Get<T>(int col, bool usedefault = true)
  125. {
  126. if (col < 0 || col >= Values.Count)
  127. {
  128. if (usedefault)
  129. return CoreUtils.GetDefault<T>();
  130. throw new Exception(string.Format("Column [{0}] does not exist!", col));
  131. }
  132. return Values[col] != null ? (T)CoreUtils.ChangeType(Values[col], typeof(T)) : CoreUtils.GetDefault<T>();
  133. }
  134. public T Get<T>(string columnname, bool usedefault = true)
  135. {
  136. var col = GetColumn(columnname);
  137. if (col < 0 || col >= Values.Count)
  138. {
  139. if (usedefault)
  140. return CoreUtils.GetDefault<T>();
  141. throw new Exception(string.Format("Column [{0}] does not exist!", columnname));
  142. }
  143. return Values[col] != null ? (T)CoreUtils.ChangeType(Values[col], typeof(T)) : CoreUtils.GetDefault<T>();
  144. }
  145. public TType Get<TSource, TType>(Expression<Func<TSource, TType>> expression, bool usedefault = true)
  146. {
  147. var colname = GetColName(expression);
  148. //String colname = CoreUtils.GetFullPropertyName(expression, ".");
  149. return Get<TType>(colname, usedefault);
  150. }
  151. public void Set<TSource, TType>(Expression<Func<TSource, TType>> expression, TType value)
  152. {
  153. var colname = GetColName(expression);
  154. //String colname = CoreUtils.GetFullPropertyName(expression, ".");
  155. Set(colname, value);
  156. }
  157. public void Set<T>(int col, T value)
  158. {
  159. while (Values.Count <= col)
  160. Values.Add(Table.Columns[Values.Count].DataType.GetDefault());
  161. Values[col] = value;
  162. }
  163. public void Set<T>(string columnname, T value)
  164. {
  165. var col = GetColumn(columnname);
  166. if (col < 0)
  167. throw new Exception("Column not found: " + columnname);
  168. while (Values.Count <= col)
  169. Values.Add(Table.Columns[Values.Count].DataType.GetDefault());
  170. Values[col] = value;
  171. //this.RowObject.SetValue(columnname, value);
  172. }
  173. public void LoadValues(IEnumerable<object?> values)
  174. {
  175. Values = values.ToList();
  176. }
  177. public T ToObject<TSource, TLink, T>(Expression<Func<TSource, TLink>> property)
  178. where TLink : IEntityLink<T>
  179. where T : BaseObject, new()
  180. {
  181. var entity = new T();
  182. entity.SetObserving(false);
  183. var prefix = CoreUtils.GetFullPropertyName(property, ".");
  184. if (!Table.Setters.TryGetValue(prefix, out var setters))
  185. {
  186. setters = new List<Action<object, object>?>();
  187. Table.Setters[prefix] = setters;
  188. }
  189. var bFirst = !setters.Any();
  190. var cols = Table.Columns.Where(x => x.ColumnName.StartsWith(prefix + ".")).ToArray();
  191. for (var i = 0; i < cols.Length; i++)
  192. {
  193. var column = cols[i].ColumnName;
  194. var prop = column.Substring((prefix + ".").Length);
  195. var value = this[column];
  196. try
  197. {
  198. if (bFirst)
  199. {
  200. var p2 = DatabaseSchema.Property(typeof(T), prop);
  201. setters.Add(p2?.Setter());
  202. }
  203. var setter = setters[i];
  204. if (setter != null && value != null)
  205. setter.Invoke(entity, value);
  206. else
  207. CoreUtils.SetPropertyValue(entity, prop, value);
  208. }
  209. catch (Exception e)
  210. {
  211. Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
  212. }
  213. }
  214. entity.CommitChanges();
  215. entity.SetObserving(true);
  216. return entity;
  217. }
  218. private string GetColName<TSource, TType>(Expression<Func<TSource, TType>> expression)
  219. {
  220. //int hash = expression.GetHashCode();
  221. //if (_accessedcolumns.ContainsKey(hash))
  222. // return _accessedcolumns[hash];
  223. var colname = CoreUtils.GetFullPropertyName(expression, ".");
  224. //_accessedcolumns[hash] = colname;
  225. return colname;
  226. }
  227. private int GetColumn(string columnname)
  228. {
  229. if (_columnindexes.ContainsKey(columnname))
  230. return _columnindexes[columnname];
  231. for (var i = 0; i < Table.Columns.Count; i++)
  232. if (Table.Columns[i].ColumnName.Equals(columnname))
  233. {
  234. _columnindexes[columnname] = i;
  235. return i;
  236. }
  237. _columnindexes[columnname] = -1;
  238. return -1;
  239. }
  240. }
  241. public static class CoreRowExtensions
  242. {
  243. public static IEnumerable<T> ToObjects<T>(this IEnumerable<CoreRow> rows)
  244. where T : BaseObject, new()
  245. {
  246. return rows.Select(x => x.ToObject<T>());
  247. }
  248. }
  249. }