How to efficiently create a list of objects inside

2019-07-12 09:04发布

问题:

So, I have an application which lies on a database. So far, the results of my queries all went into a DataTable object like this:

DataTable data = new DataTable();
data.Load(someQuery.ExecuteReader());

Now, I want to load my data into a list of a strongly typed objects. Something like this:

List<MyClass> data = someQuery.Load<MyClass>();

However, my first take on writing that method ended up running almost three times slower than DataTable.Load(IDataReader) method. Basically, I have user GetConstructor(null).Invoke(null) to create and object and I have used PropertyInfo.SetValue(reader.GetValue()) to fill it with data.

Is there a better way to do this?

The method used:

    public List<T> LoadData<T>(DbCommand query)
    {
        Type t = typeof(T);

        List<T> list = new List<T>();
        using (IDataReader reader = query.ExecuteReader())
        {
            while (reader.Read())
            {
                T newObject = (T)t.GetConstructor(null).Invoke(null);

                for (int ct = 0; ct < reader.FieldCount; ct++)
                {
                    PropertyInfo prop = t.GetProperty(reader.GetName(ct));
                    if (prop != null)
                        prop.SetValue(newObject, reader.GetValue(ct), null);
                }

                list.Add(newObject);
            }
        }

        return list;
    }

回答1:

To do this efficiently requires metaprogramming. You can use libraries to help. For example, "FastMember" includes a TypeAccessor which provides fast access to instance creation and member-access by name. However, this example is also basically exactly how "dapper" works, so you could just use dapper:

int id = ...
var data = connection.Query<Order>(
    "select * from Orders where CustomerId = @id",
    new { id }).ToList();

You can also open up the "dapper" code to see what it does.



回答2:

You can execute your query using linQ and get the Generic List and then if you want to conver it to DataTable then use the following Code, it may help you.

public DataTable ListToDataTable<T>(IEnumerable<T> list)
    {
        PropertyDescriptorCollection properties =
            TypeDescriptor.GetProperties(typeof(T));
        DataTable table = new DataTable();
        foreach (PropertyDescriptor prop in properties)
            table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
        foreach (T item in list)
        {
            DataRow row = table.NewRow();
            foreach (PropertyDescriptor prop in properties)
                row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
            table.Rows.Add(row);
        }
        return table;
    }

it will work for any strongly type class. Please check the time it takes to execute.

Thanks,