【问题标题】:How to map datatable columns to properties of DTO object of Type T如何将数据表列映射到类型 T 的 DTO 对象的属性
【发布时间】:2019-09-26 18:45:13
【问题描述】:

如何使用 LINQ 查询或 Lambda 表达式将数据表列与类型 T 的 DTO 对象的属性映射。这应该会自动映射到任何 DTO。如果有办法做到这一点,而无需对数据表的列名进行硬编码

DataTable dt = db.GetEmployees();


foreach(DataRow dr in dt.Rows)
{
    var obj = new T();
    PropertyInfo[] prop  = obj.GetType().GetProperties();



    var results = dt.AsEnumerable().Select(dr => new T
        {
            ///How to directly map type T properties in prop with columns in datatable dt

        FirstName = ?

        //Expecting something like this
                //FirstName = columnName of dt here

        }     
}

【问题讨论】:

  • 你想避免使用反射吗?
  • @LawrenceZahner 可以使用反射。我只想避免手动逐行 foreach 属性和对数据表中的列名进行硬编码
  • 好的,这开辟了一些可能性。 DataTable 的列名是否与 T 中的属性名完全匹配?
  • 不完全匹配,例如Property name = PhoneNumber , Column Name = Phone Number (WorkPhone)
  • 一个我没有探索过的替代品(所以不能说它是否确实有效)是 automapper 库,它有利于映射,只是不确定它是否适用于对象的数据表

标签: c# linq reflection mapping dto


【解决方案1】:

我们可以使用反射将数据表的列转换为 DTO 对象的属性。就我而言,我实际上是将其转换为列表,这是代码:

        private IEnumerable<T> ConvertToEnumerable(DataTable dt)
        {
            List<T> ls = new List<T>();

            // get all the column names from datatable
            var columnNames = dt.Columns.Cast<DataColumn>().Select(c => c.ColumnName).ToList();

            //dto so all properties should be public
            var dtoProperties = typeof(T).GetProperties(); 

            foreach (DataRow row in dt.Rows)
            {
                // create  a new DTO object
                var item = new T();

                // for each property of the dto
                foreach (var property in dtoProperties)
                {
                    var objPropName = property.Name;

                    // I am using the column map dictionary to convert the 
                    // DTO property name into my datatable column name
                    // but you can omit this step if your names in DTO 
                    // and datatable columns are same
                    var dbPropName = ColumnMap[property.Name];
                    if (columnNames.Contains(dbPropName))
                    {
                        if (row[dbPropName] != DBNull.Value)
                        {
                            // set the value
                            property.SetValue(item, row[dbPropName], null);
                        }
                    }
                }

                // add the DTO to the list
                ls.Add(item);
            }
            return ls;
        }

请注意,由于我们正在执行new T(),因此需要对类进行约束。为了完整性,columnMap 的约束和定义是:

public class Repository<T> : IRepository<T> where T : new()
    {
        private DbManager context = null;

        public Dictionary<string, string> ColumnMap { get; set; }
        ...
        ...
     }

并且列名映射存储为:

public class RepositoryMap
{

    public static Dictionary<string, string> ObjectToDatatableMap = new Dictionary<string, string>
    {
        // keep in mind that key is the DTO property
        // value is the datatable columm name
        {"Id", "ID"},
        {"Owner", "OWNER"},
        {"QueryName", "QUERY NAME"},
        {"PhoneNumber", "Phone Number"},
    };
}

【讨论】:

  • ColumnMap是怎么做的?您是对列名进行硬编码还是如何处理它。如果可能,请提供一些示例代码帮助如何在不进行硬编码的情况下完成映射
  • @user1030181 您必须在某处对该映射进行硬编码,在我的情况下,我选择创建一个 columnMap 字典,您也可以创建一个基于规则的系统,但这仍然是硬编码。一个简单的规则是从数据表列名中删除下划线,您必须手动创建规则集并运行转换。
  • 你能把你的字典的示例代码发给我吗
  • @user1030181 已发布
  • 那么可以用 LINQ 查询吗?
猜你喜欢
  • 2022-01-01
  • 2022-10-22
  • 1970-01-01
  • 2018-12-29
  • 2021-11-19
  • 2022-08-18
  • 2022-07-06
  • 2021-12-10
  • 2020-11-16
相关资源
最近更新 更多