2009-11-10 3 views
3

Я создал общий список и заполнил некоторые объекты. Затем список, упомянутый выше, был преобразован в DataTable для использования в DataGridView. Проблема в том, когда я хочу получить строку из этой сетки, у меня есть DataRow. Я хотел снова преобразовать это в свой объект, но не знаю, как это сделать. Может быть, вы могли бы привести пример?Преобразование DataRow в объект

Благодаря

+0

немного кода будет полезен ... –

ответ

9

Предполагая, что вы будете использовать класс MyObject, определяется следующим образом:

class MyObject 
{ 
    public string Foo { get; set; } 
    public int Foo { get; set; } 
} 

Вы могли бы сделать что-то вроде этого:

using System.Data.DataSetExtensions; 

... 

List<MyObject> list = (from row in table.AsEnumerable() 
         select new MyObject 
         { 
          Foo = row.Field<string>("foo"), 
          Bar = row.Field<int>("bar") 
         }).ToList(); 
11

Ну, если вы не можете или не будет использовать «ORM» (объектно-реляционный картограф, такой как Linq-to-SQL или NHibernate - это именно то, что делают эти инструменты, и для вас это очень хорошо), вам придется сделать это самостоятельно.

Преобразование DataRow в объект домена модели довольно скучный код, на самом деле:

public Customer ConvertRowToCustomer(DataRow row) 
{ 
    Customer result = new Customer(); 

    result.ID = row.Field<int>("ID"); 
    result.Name = row.Field<string>("CustomerName"); 
    ..... // and so on 

    return result; 
} 

Самой большой проблемой здесь делает этот незыблемую и регулировать (или избежать) все возможные ошибки (например, поле существа NULL и т. Д.).

Другой возможностью было бы иметь конструктор по типу объекта модели домена, который принимает параметр DataRow в качестве параметра и создает из него новый объект.

Марк

+0

+1 для предложения ORM. –

+0

Спасибо, Могу ли я использовать это (конечно, с некоторыми изменениями), когда у меня есть много типов для преобразования. Например, у одного DataTable есть записи с данными Клиента и другими записями с адресами? Должен ли я использовать отражение? – arek

+0

Вы можете, конечно, использовать отражение, чтобы обобщить этот метод для любого типа и еще больше улучшить ухудшенную производительность, возникающую в результате отражения, вы можете использовать Reflection.Emit для создания динамических сборок, а затем добавить некоторую ленивую загрузку в свои коллекции и в конце в тот день, когда вы поймете, что люди уже научились об этих проблемах и изобрели ORM, такие как NHibernate, Entity Framework, ...и вы поймете, что вы приложили усилия к тому, что уже существует и что вы можете использовать бесплатно. –

1

Почему бы не просто поставить свои объекты в BindingList <>, а не список <>? Затем вы можете пропустить преобразование в DataTable и обратно. Возможно, вам понадобится реализовать на ваших объектах INotifyPropertyChanged, но как только они попадут в BindingList, изменения в datagrid будут автоматически применены к вашим базовым объектам.

Сортировка может быть обработана путем сортировки списка вручную по щелчку заголовка столбца или путем наследования от BindingList <> и реализации функции сортировки внутри него - тогда щелчок по заголовку автоматически сортирует список - никакого кода не требуется.

0

Ну, в настоящее время это проще, используя ORM. Но если все же вы используете старую моду вы можете пойти с довольно простой класс расширения, чтобы сделать работу для Вас, используя немного отражения и общих методов и лямбда следующим образом:

public static class MapperExtensionClass 
{ 

     public static IEnumerable<MyClassType> ToMyClassTypeEnumerable(this DataTable table) 
     { 
      return table.AsEnumerable().Select(r => r.ToMyClassType()); 
     } 

     public static MyClassType ToMyClassType(this DataRow row) 
     {    
      return row.ToObject<MyClassType>(); 
     } 

     public static T ToObject<T>(this DataRow row) where T: new() 
     { 
      T obj = new T(); 
      foreach (PropertyInfo property in typeof(T).GetProperties()) 
      { 
       if (row.Table.Columns.Contains(property.Name)) 
       { 
        property.SetValue(obj, property.PropertyType.ToDefault(row[property.Name])); 
       } 
      } 

      return obj; 
     } 


     public static object ToDefault(this Type type, object obj) 
     { 
      if (type == null) 
       throw new Exception("Customized exception message"); 

      var method = typeof(MapperExtensionClass) 
       .GetMethod("ToDefaultGeneric", BindingFlags.Static | BindingFlags.Public); 

      var generic = method.MakeGenericMethod(type); 

      return generic.Invoke(null, new object[] { obj });    
     } 

     public static T ToDefaultGeneric<T>(object obj) 
     { 
      if (obj == null || obj == DBNull.Value) 
      { 
       return default(T); 
      } 
      else 
      { 
       return (T)obj; 
      } 
     } 
} 

Вы также должны помнить, Объекты GridView могут связывать множество типов источников данных. Итак, это ваше решение от дизайнерского пункта о том, с чем вам следует идти.

Смежные вопросы