using System; using System.Collections.Generic; using System.Data.SqlClient; using System.Collections.ObjectModel; using FastMember; using System.Linq; namespace Knoks.Framework.DataAccess { public class DataResult { public Dictionary Тables { get; set; } = new Dictionary(); public Dictionary OutputParams { get; set; } = new Dictionary(StringComparer.OrdinalIgnoreCase); public int? ReturnValue { get; set; } } public class Row { public ReadOnlyDictionary ColumnNames { get; private set; } public ReadOnlyCollection ColumnValues { get; private set; } public Row(ReadOnlyDictionary columnNames, ReadOnlyCollection columnValues) { ColumnNames = columnNames; ColumnValues = columnValues; } public object this[int columnIndex] { get { return ColumnValues[columnIndex]; } } public object this[string columnName] { get { return ColumnValues[ColumnNames[columnName]]; } } public T To() where T : class, new() { return To(ColumnNames, ColumnValues); } public T ToMapped(Func mapper = null) where T : class, new() { var accessor = TypeAccessor.Create(typeof(T)); var meta = Table.Parse(accessor, ColumnNames, mapper); return Process(accessor, meta); } internal T Process(TypeAccessor accessor, Dictionary meta) where T : class, new() { var res = new T(); foreach (var c in meta) { try { accessor[res, c.Key.Name] = ColumnValues[c.Value]; } catch (Exception ex) { try { accessor[res, c.Key.Name] = Convert.ChangeType(c.Value, c.Key.Type); } catch (Exception exx) { throw new ArgumentException(c.Key.Name + ": " + ex.Message, exx); } } } return res; } public static T To(IDictionary ColumnNames, IList ColumnValues) where T : class, new() { var res = new T(); var accessor = TypeAccessor.Create(res.GetType()); foreach (var cn in accessor.GetMembers()) { int columnIndex; try { if (ColumnNames.TryGetValue(cn.Name, out columnIndex)) accessor[res, cn.Name] = ColumnValues[columnIndex]; } catch (Exception ex) { throw new ArgumentException(cn.Name + ": " + ex.Message, ex); } } return res; } } public class Table { private Dictionary _columnNames = new Dictionary(StringComparer.OrdinalIgnoreCase); public ReadOnlyDictionary ColumnNames { get; } private List _rows = new List(); public ReadOnlyCollection Rows { get; } public Table(SqlDataReader reader) { ColumnNames = new ReadOnlyDictionary(_columnNames); Rows = new ReadOnlyCollection(_rows); int fieldCount = reader.FieldCount; for (int i = 0; i < fieldCount; i++) _columnNames.Add(reader.GetName(i), i); while (reader.Read()) { var rowValues = new object[fieldCount]; for (var i = 0; i < rowValues.Length; i++) { var val = reader[i]; rowValues[i] = val == DBNull.Value ? null : val; } _rows.Add(new Row(ColumnNames, new ReadOnlyCollection(rowValues))); } } public Row this[int rowIndex] { get { return _rows[rowIndex]; } } public IEnumerable ToList() where T : class, new() { return _rows.Select(r => r.To()); } public IEnumerable ToListMapped(Func mapper = null) where T : class, new() { var accessor = TypeAccessor.Create(typeof(T)); var meta = Parse(accessor, ColumnNames, mapper); return _rows.Select(r => r.Process(accessor, meta)); } internal static Dictionary Parse(TypeAccessor accessor, IDictionary ColumnNames, Func mapper = null) where T : class, new() { return accessor.GetMembers().Select(cn => { int columnIndex; string name = mapper == null ? cn.Name : mapper(cn.Name); if (!ColumnNames.TryGetValue(name, out columnIndex)) { columnIndex = -1; } return new { cn, columnIndex }; }).Where(it => it.columnIndex != -1).ToDictionary(it => it.cn, it => it.columnIndex); } public IEnumerable ToPrimitiveList() { return _rows.Select(r => (T)r.ColumnValues.First()); } } }