Преобразование кадра данных Deedle в C# список пользовательского класса
Я получаю данные из внешнего API в качестве фрейма данных Deedle. Мне нужно взять эти данные и преобразовать их в список пользовательских классов для вставки в базу данных через Entity Framework.
Кто-нибудь сможет указать мне правильное направление? Я раньше не пользовался Deedle, и у меня возникают проблемы с поиском лучшего способа извлечения данных.
Пользовательский объект, который мне нужно заполнить, выглядит следующим образом:
public class FrameData
{
public string SecurityId { get; set; }
public string FieldName { get; set; }
public DateTime Date { set; get; }
public decimal value { get; set; }
}
Спасибо ник
2 ответа
Есть много способов получить данные из фрейма Deedle. Позволяет ли Entity Framework использовать интерфейсы? Если так, то есть хорошая функция GetRowsAs
что позволяет вам сделать это:
// Given a simple Person interface
public interface Person {
int Age { get; }
string Name{ get; }
}
// And a sample data frame with some data
Frame<int, string> df = Frame.FromValues(new[] {
Tuple.Create(1, "Name", (object) "One"),
Tuple.Create(2, "Name", (object) "Two"),
Tuple.Create(1, "Age", (object) 42),
Tuple.Create(2, "Age", (object) 21)
});
// You can get an array of rows using
var rows = df.GetRowsAs<Person>();
Если Entity Framework не может обрабатывать интерфейсы, этот метод, к сожалению, не будет работать. В этом случае вам понадобится что-то вроде:
var rows =
df.Rows.Select(row =>
new Person { Name = row.Value.GetAs<string>("Name"),
Age = row.Value.GetAs<int>("Age"))).Observations;
То, что сказал @Tomas Petricek, является хорошим примером, но, имея много разных классов, это может стать проблемой.
Итак, здесь я сделал пример, как динамически преобразовать его в определенный класс и использовать атрибут для отображения между свойством и индексом столбца.
// Mapp a key to an index
public class IndexAttribute: Attribute(){
public int Index { get; private set; }
public IndexAttribute(int index){
Index = index;
}
}
public class FrameData
{
[IndexAttribute(0)]
public string SecurityId { get; set; }
[IndexAttribute(3)]
public string FieldName { get; set; }
[IndexAttribute(2)]
public DateTime Date { set; get; }
[IndexAttribute(1)]
public decimal value { get; set; }
}
// create a class the convert the frame to class
public static List<T> Convert<T>(this DataTable data) where T: class
{
var list = new List<T>();
foreach(var row in data.Rows){
object item = Activator.CreateInstance(typeof(T));
var props = typeof(T).GetProperties();
foreach(var p in props){
var index = p.GetCustomAttribute<IndexAttribute>()?.Index ?? -1;
if (index< 0)
continue;
if (table.Columns.length > index) // if the index exist
{
var value = row[index]; // get the value.
if (value == null)
continue; // ignore null value
if (prop.PropertyType == typeof(string))
prop.SetValue(item, value.ToString());
if (prop.PropertyType == typeof(DateTime))
prop.SetValue(item, DateTime.Parse(value.ToString()));
// .. now check for decimal, int etc
}
}
list.Add(item);
}
return list;
}
And now all you need is to call the function
List<Person> persons = df.Convert<Person>(); // that all