2012-06-30 101 views
9

目前,我使用的是这样的:如何将SQL查询的结果映射到对象上?

try 
    { 
     dr = SQL.Execute(sql); 

     if(dr != null) { 
     while(dr.Read()) { 
      CustomObject c = new CustomObject(); 
      c.Key = dr[0].ToString(); 
      c.Value = dr[1].ToString(); 
      c.Meta = dr[2].ToString(); 
      customerInfo.CustomerList.Add(c); 
     } 
     } 
     else 
     { 
      customerInfo.ErrorDetails="No records found"; 
     } 

代替我的手工做assigments,有没有办法直接做到这一点映射(假设列名称匹配与字段名)。

然而,一个要求是我想通过使用sql查询而不是使用基于纯LINQ的方法来执行此操作。首先,SQL查询足够大,涉及复杂的JOIN,并且已经过彻底测试,因此我现在不想引入更多的错误。有什么建议么?

+2

请注意,您*可以*使用LINQ自定义SQL查询,并且它会自动将查询结果中的字段映射到您提供的通用对象类型。请参阅[**'DataContext.ExecuteQuery' **](http://msdn.microsoft.com/zh-cn/library/bb361109.aspx) – mellamokb

+0

@mellamokb:你能告诉我如何?或者至少将我指向一些资源,或者我应该搜索什么? – Legend

+0

看看我添加的链接,这是您需要的特定方法。这个页面上也有例子。 – mellamokb

回答

4

一个简单的解决方案是为您的CustomObject制作一个构造函数,其中需要DataRow(从示例中,如果是另一个类,请更正我)。

然后在你的新构造函数中,像你在你自己的例子中那样做。

public CustomObject(DataRow row) 
{ 
    Key = row[0].ToString(); 
    // And so on... 
} 

的另一种方式是引进仿制药,并进行了新的功能,在您的SQL级

例(接过从Passing arguments to C# generic new() of templated type代码):

// This function should reside in your SQL-class. 
public IEnumerable<T> ExecuteObject<T>(string sql) 
{ 
    List<T> items = new List<T>(); 
    var data = ExecuteDataTable(sql); // You probably need to build a ExecuteDataTable for your SQL-class. 
    foreach(var row in data.Rows) 
    { 
     T item = (T)Activator.CreateInstance(typeof(T), row); 
     items.Add(item); 
    } 
    return items; 
} 

用法示例:

public IEnumerable<CustomObject> GetCustomObjects() 
{ 
    return SQL.ExecuteObject<CustomObject>("SELECT * FROM CustomObject"); 
} 

我已经在LinqPad中测试过这段代码,它应该可以工作。

3

您可以通过为您的需求创建通用方法来实现。您也可以将您的新方法作为数据表的扩展名。

public static List<T> ToList<T>(this DataTable table) where T : class, new() 
{ 
    try 
    { 
     List<T> list = new List<T>(); 

     foreach (var row in table.AsEnumerable()) 
     { 
      T obj = new T(); 

      foreach (var prop in obj.GetType().GetProperties()) 
      { 
       try 
       { 
        PropertyInfo propertyInfo = obj.GetType().GetProperty(prop.Name); 
        propertyInfo.SetValue(obj, Convert.ChangeType(row[prop.Name], propertyInfo.PropertyType), null); 
       } 
       catch 
       { 
        continue; 
       } 
      } 

      list.Add(obj); 
     } 

     return list; 
    } 
    catch 
    { 
     return null; 
    } 
} 

}

用法:

DataTable dtCustomer = GetCustomers(); 
    List<CustomObject> CustomObjectList = dtCustomer.ToList<CustomObject>(); 
2

你应该看看MicroORMs。与提供必须使用的SDL的常规ORM不同,MicroORM允许您使用自己的SQL查询,并仅提供从SQL结果集到C#对象的映射,以及从C#对象到SQL参数的映射。

我最喜欢的是PetaPoco,它还提供了一个查询生成器,它使用您自己的SQL,但对参数编号进行了一些简洁的操作。

0

下面的函数接受一个SQL字符串和一个对象,它要求对象在select语句中为每个列都有一个属性。该对象必须实例化。

公共对象SqlToSingleObject(字符串sSql,对象o){

 MySql.Data.MySqlClient.MySqlDataReader oRead; 
     using (ConnectionHelper oDb = new ConnectionHelper()) 
     { 
      oRead = oDb.Execute(sSql); 
      if (oRead.Read()) 
      { 

       for (int i = 0; i < oRead.FieldCount; i++) 
       { 

        System.Reflection.PropertyInfo propertyInfo = o.GetType().GetProperty(oRead.GetName(i)); 
        propertyInfo.SetValue(o, Convert.ChangeType(oRead[i], propertyInfo.PropertyType), null); 
       } 
       return o; 
      } 
      else 
      { 
       return null; 

      } 

     } 

    } 
+0

这是什么意思?如果你要创建所有的属性,为什么不自己构建对象。 – MattE

1

假设:,如果你只需要进行序列化或简单的点对点输出对象。

您可以使用ExpandoObjectSqlDataReader.GetSchemaTable()这样的:

private IEnumerable<dynamic> ReaderToAnonymmous(SqlCommand comm) { 
     using (var reader = comm.ExecuteReader()) { 
      var schemaTable = reader.GetSchemaTable(); 

      List<string> colnames = new List<string>(); 
      foreach (DataRow row in schemaTable.Rows) { 
       colnames.Add(row["ColumnName"].ToString()); 
      } 

      while (reader.Read()) { 
       var data = new ExpandoObject() as IDictionary<string, Object>; 
       foreach (string colname in colnames) { 
        var val = reader[colname]; 
        data.Add(colname, Convert.IsDBNull(val) ? null : val); 
       } 

       yield return (ExpandoObject)data; 
      } 
     } 
    } 

虽然有更快的发布解决方案(我张贴的ad-hoc SQL /读卡器结果/输出以此作为替代偷懒的做法)。

+0

这真棒,正是我一直在寻找。我是控制台应用程序,它可以从存储过程生成Excel中的报告,并且使用这段代码我不必在应用程序中映射这些过程。谢谢。 – v1n1akabozo

相关问题