C# 如何将sql查询的结果映射到对象上?
目前,我正在使用类似以下内容:C# 如何将sql查询的结果映射到对象上?,c#,sql,C#,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.Me
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";
}
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;
}
}
}
using (var connection = new SqlConnection(ConnectionString))
{
connection.Open();
IList<CustomObject> result = connection.Query<CustomObject>(sql, commandType: CommandType.Text).ToList();
}
有没有办法直接进行映射(假设列名与字段名匹配),而不是手动进行分配
然而,有一个要求是,我希望通过当前使用sql查询的方法来实现这一点,而不是使用纯粹基于LINQ的方法。首先,SQL查询足够大,涉及复杂的连接,并且已经过全面测试,所以我现在不想引入更多的bug。有什么建议吗?一个简单的解决方案是为您的
CustomObject
创建一个构造函数,它接受DataRow
(来自示例,因此如果它是另一个类,请更正我)
在您的新构造函数中,按照您在自己的示例中所做的做
public CustomObject(DataRow row)
{
Key = row[0].ToString();
// And so on...
}
另一种方法是引入泛型,并在SQL类中创建一个新函数
示例(代码取自):
//此函数应驻留在SQL类中。
公共IEnumerable可执行对象(字符串sql)
{
列表项=新列表();
var data=ExecuteDataTable(sql);//您可能需要为sql类构建一个ExecuteDataTable。
foreach(data.Rows中的变量行)
{
T item=(T)Activator.CreateInstance(typeof(T),row);
项目。添加(项目);
}
退货项目;
}
用法示例:
public IEnumerable<CustomObject> GetCustomObjects()
{
return SQL.ExecuteObject<CustomObject>("SELECT * FROM CustomObject");
}
public IEnumerable GetCustomObjects()
{
返回SQL.ExecuteObject(“从CustomObject中选择*);
}
我已经在LinqPad中测试了这段代码,它应该可以工作。您可以通过为您的需求创建一个通用方法来实现。还可以将新方法作为数据表的扩展
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;
}
}
公共静态列表ToList(此数据表),其中T:class,new()
{
尝试
{
列表=新列表();
foreach(表中的var行。AsEnumerable())
{
T obj=新的T();
foreach(obj.GetType().GetProperties()中的var prop)
{
尝试
{
PropertyInfo PropertyInfo=obj.GetType().GetProperty(prop.Name);
propertyInfo.SetValue(obj,Convert.ChangeType(行[prop.Name],propertyInfo.PropertyType),null);
}
抓住
{
继续;
}
}
列表。添加(obj);
}
退货清单;
}
抓住
{
返回null;
}
}
}
用法:
DataTable dtCustomer = GetCustomers();
List<CustomObject> CustomObjectList = dtCustomer.ToList<CustomObject>();
DataTable dtCustomer=GetCustomers();
List CustomObjectList=dtCustomer.ToList();
您应该研究MicroORMs。与提供必须使用的SDL的常规ORM不同,MicroORM允许您使用自己的SQL查询,并且只提供从SQL结果集到C#对象以及从C#对象到SQL参数的映射
我最喜欢的是,它还提供了一个查询生成器,它使用您自己的SQL,但对参数号进行了一些整洁的操作。以下函数接受一个SQL字符串和一个对象,它要求对象在select语句中的每一列都有一个属性。必须实例化该对象
public object SqlToSingleObject(string sSql, object 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;
}
}
}
public对象SqlToSingleObject(字符串sSql,对象o)
{
MySql.Data.MySqlClient.MySqlDataReader或ead;
使用(ConnectionHelper oDb=new ConnectionHelper())
{
oRead=oDb.Execute(sSql);
if(oRead.Read())
{
对于(int i=0;i
假设:如果您只需要用于序列化或简单即席输出的对象
您可以像这样使用ExpandoObject
和SqlDataReader.GetSchemaTable()
:
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";
}
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;
}
}
}
using (var connection = new SqlConnection(ConnectionString))
{
connection.Open();
IList<CustomObject> result = connection.Query<CustomObject>(sql, commandType: CommandType.Text).ToList();
}
private IEnumerable readerToAnonymous(SqlCommand comm){
使用(var reader=comm.ExecuteReader()){
var schemaTable=reader.GetSchemaTable();
List colnames=新列表();
foreach(schemaTable.Rows中的DataRow行){
添加(行[“ColumnName”].ToString());
}
while(reader.Read()){
var data=新的ExpandooObject()作为IDictionary;
foreach(colnames中的字符串colname){
var val=读取器[colname];
data.Add(colname,Convert.IsDBNull(val)?null:val);
}
收益率返回(ExpandoObject)数据;
}
}
}
尽管发布了更快的解决方案(我发布了这篇文章,作为临时SQL/Reader结果/输出的替代惰性方法) 在搜索此答案时,我发现您可以使用Dapper library: 您可以使用以下内容:
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";
}
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;
}
}
}
using (var connection = new SqlConnection(ConnectionString))
{
connection.Open();
IList<CustomObject> result = connection.Query<CustomObject>(sql, commandType: CommandType.Text).ToList();
}
使用(var连接=新的SqlConnection(ConnectionString))
{
connection.Open();
IList result=connection.Query(sql,commandType:commandType.Text).ToList();
}
的答案很好,但是,如果列名与属性名不完全匹配,则它不起作用
因此,首先您需要创建一个自定义属性。然后使用您试图反序列化的类中的属性,最后,您希望反序列化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;
}
}
类进行反序列化
接下来,在我们要填充的类中,我们将使用我们刚才使用的属性[MySqlColName]
声明将链接到类中属性的列名