目前,我使用的是这样的:
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";
}
Run Code Online (Sandbox Code Playgroud)
而不是我手动执行分配,有没有办法直接执行此映射(假设列名称与字段名称匹配).
然而,一个要求是我希望通过我当前使用sql查询的方法而不是使用基于纯LINQ的方法来实现这一点.首先,SQL查询足够大,涉及复杂的JOIN并且已经过彻底测试,因此我不想在此时引入更多错误.有什么建议?
一个简单的解决办法是让一个构造你CustomObject是需要DataRow(从例如,所以如果它是另一个类,请指正).
在您的新构造函数中,按照您自己的示例执行操作.
public CustomObject(DataRow row)
{
Key = row[0].ToString();
// And so on...
}
Run Code Online (Sandbox Code Playgroud)
另一种方法是引入泛型,并在SQL类中创建一个新函数
示例(从传递参数到模板化类型的C#generic new()的代码):
// 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;
}
Run Code Online (Sandbox Code Playgroud)
用法示例:
public IEnumerable<CustomObject> GetCustomObjects()
{
return SQL.ExecuteObject<CustomObject>("SELECT * FROM CustomObject");
}
Run Code Online (Sandbox Code Playgroud)
我已经在LinqPad中测试了这段代码,它应该可以工作.
小智 6
您可以通过为您的需求创建通用方法来实现.您还可以将新方法作为数据表的扩展名.
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;
}
}
Run Code Online (Sandbox Code Playgroud)
}
用法:
DataTable dtCustomer = GetCustomers();
List<CustomObject> CustomObjectList = dtCustomer.ToList<CustomObject>();
Run Code Online (Sandbox Code Playgroud)
@user1553525的答案很好,但是,如果您的列名称与属性名称不完全匹配,则它不起作用。
因此,首先您需要创建一个自定义属性。然后使用您要反序列化的类中的属性,最后,您要反序列化 DataTable。
我们创建一个自定义属性,该属性将应用于我们类内部的属性。我们创建的类具有属性Name,稍后我们将使用该属性从数据表中获取正确的列。
[AttributeUsage(AttributeTargets.Property, Inherited = false)]
public class MySqlColName : Attribute
{
private string _name = "";
public string Name { get => _name; set => _name = value; }
public MySqlColName(string name)
{
_name = name;
}
}
Run Code Online (Sandbox Code Playgroud)
接下来,在我们要填充的类中,我们将声明将使用[MySqlColName]我们刚刚创建的属性链接到类中的属性的列名称。
但是,如果属性名称与数据库列相同,我们不需要在属性中指定列名称,因为函数.ToList<>()将采用属性名称中的列名称。
public class EventInfo
{
[MySqlColName("ID")]
public int EventID { get; set; }
//Notice there is no attribute on this property?
public string Name { get; set; }
[MySqlColName("State")]
public string State { get; set; }
[MySqlColName("Start_Date")]
public DateTime StartDate { get; set; }
[MySqlColName("End_Date")]
public DateTime EndDate { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
最后,我们通过添加检查来修改@user1553525的答案,以查看是否已提供我们的自定义属性。如果是,那么我们将列的名称设置为提供的名称,否则,我们使用属性名称(请参阅 try 块内的代码)。
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
{
//Set the column name to be the name of the property
string ColumnName = prop.Name;
//Get a list of all of the attributes on the property
object[] attrs = prop.GetCustomAttributes(true);
foreach (object attr in attrs)
{
//Check if there is a custom property name
if (attr is MySqlColName colName)
{
//If the custom column name is specified overwrite property name
if (!colName.Name.IsNullOrWhiteSpace())
ColumnName = colName.Name;
}
}
PropertyInfo propertyInfo = obj.GetType().GetProperty(prop.Name);
//GET THE COLUMN NAME OFF THE ATTRIBUTE OR THE NAME OF THE PROPERTY
propertyInfo.SetValue(obj, Convert.ChangeType(row[ColumnName], propertyInfo.PropertyType), null);
}
catch
{
continue;
}
}
list.Add(obj);
}
return list;
}
catch
{
return null;
}
}//END METHOD
Run Code Online (Sandbox Code Playgroud)
最后,我们可以调用该.ToList<>()方法并获取序列化对象的列表
List<EventInfo> CustomObjectList;
using (DataTable dtCustomer = GetDataTable("SELECT * FROM EventIndex"))
{
CustomObjectList = dtCustomer.ToList<EventInfo>();
}
Run Code Online (Sandbox Code Playgroud)
旁注:我使用了一些自定义方法
public static bool IsNullOrWhiteSpace(this string x)
{
return string.IsNullOrWhiteSpace(x);
}
public static DataTable GetDataTable(string Query)
{
MySqlConnection connection = new MySqlConnection("<Connection_String>");
try
{
DataTable data = new DataTable();
connection.Open();
using (MySqlCommand command = new MySqlCommand(Query, connection))
{
data.Load(command.ExecuteReader());
}
return data;
}
catch (Exception ex)
{
// handle exception here
Console.WriteLine(ex);
throw ex;
}
finally
{
connection.Close();
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
43910 次 |
| 最近记录: |