How can I map the results of a sql query onto objects?

后端 未结 7 1658
灰色年华
灰色年华 2021-02-01 20:37

Currently, I am using something like this:

    try
    {
      dr = SQL.Execute(sql);

      if(dr != null) {
         while(dr.Read()) {
           CustomObject         


        
7条回答
  •  清歌不尽
    2021-02-01 21:22

    @user1553525's answer is great, however, if your column names do not match up exactly with your property names it does not work.

    So first you would want to create a custom attribute. Then use the attribute in your class that you are trying to deserialize, finally, you want to deserialize the DataTable.

    Custom Attribute

    We create a custom attribute that will be applied to the properties inside of our class. We create the class to have the property Name that we will use later to get the correct column from our DataTable.

    [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;
        }
    }
    

    Class to deserialize

    Next, in the class that we are going to populate, we are going to declare the column names that will link to the properties in the class using the attribute [MySqlColName] that we just created.

    However, if the property name is the same as the database column we do not need to specify the column name in an attribute because the .ToList<>() function will assume the name of the column from the properties name.

    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; }
    
    }
    

    DataTable ToList Extension Method

    Finally, we modify @user1553525's answer by adding in a check to see if our custom attribute has been provided. If it is then we set the name of the column to the name provided, otherwise, we use the property name (see code inside of the try block).

    public static List ToList(this DataTable table) where T : class, new()
    {
        try
        {
            List list = new List();
    
            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
    

    Usage

    Finally, we can call the .ToList<>() method and get a list of serialized objects

    List CustomObjectList;
    
    using (DataTable dtCustomer = GetDataTable("SELECT * FROM EventIndex"))
    {
        CustomObjectList = dtCustomer.ToList();
    }
    

    Side Note: I have a few custom methods that I used

    public static bool IsNullOrWhiteSpace(this string x)
    {
        return string.IsNullOrWhiteSpace(x);
    }
    
    public static DataTable GetDataTable(string Query)
    {
        MySqlConnection connection = new MySqlConnection("");
        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();
        }            
    }
    

提交回复
热议问题