Knocks/BackEnd/Knoks.Framework/DataAccess/DataResult.cs

162 lines
5.4 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<short, Table> Тables { get; set; } = new Dictionary<short, Table>();
public Dictionary<string, object> OutputParams { get; set; } = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
public int? ReturnValue { get; set; }
}
public class Row
{
public ReadOnlyDictionary<string, int> ColumnNames { get; private set; }
public ReadOnlyCollection<object> ColumnValues { get; private set; }
public Row(ReadOnlyDictionary<string, int> columnNames, ReadOnlyCollection<object> 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<T>() where T : class, new()
{
return To<T>(ColumnNames, ColumnValues);
}
public T ToMapped<T>(Func<string, string> mapper = null) where T : class, new()
{
var accessor = TypeAccessor.Create(typeof(T));
var meta = Table.Parse<T>(accessor, ColumnNames, mapper);
return Process<T>(accessor, meta);
}
internal T Process<T>(TypeAccessor accessor, Dictionary<Member, int> 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<T>(IDictionary<string, int> ColumnNames, IList<object> 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<string, int> _columnNames = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
public ReadOnlyDictionary<string, int> ColumnNames { get; }
private List<Row> _rows = new List<Row>();
public ReadOnlyCollection<Row> Rows { get; }
public Table(SqlDataReader reader)
{
ColumnNames = new ReadOnlyDictionary<string, int>(_columnNames);
Rows = new ReadOnlyCollection<Row>(_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<object>(rowValues)));
}
}
public Row this[int rowIndex]
{
get { return _rows[rowIndex]; }
}
public IEnumerable<T> ToList<T>() where T : class, new()
{
return _rows.Select(r => r.To<T>());
}
public IEnumerable<T> ToListMapped<T>(Func<string,string> mapper = null) where T : class, new()
{
var accessor = TypeAccessor.Create(typeof(T));
var meta = Parse<T>(accessor, ColumnNames, mapper);
return _rows.Select(r => r.Process<T>(accessor, meta));
}
internal static Dictionary<Member, int> Parse<T>(TypeAccessor accessor, IDictionary<string, int> ColumnNames, Func<string, string> 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<T> ToPrimitiveList<T>()
{
return _rows.Select(r => (T)r.ColumnValues.First());
}
}
}