Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I populate a class from the results of a SQL query in C#?

I've got a class like this:

public class Product
{
    public int ProductId { get; private set; }
    public int SupplierId { get; private set; }

    public string Name { get; private set; }
    public decimal Price { get; private set; }
    public int Stock { get; private set; }
    public int PendingStock { get; private set; }
}

I can fetch those details from my database like this:

SELECT product_id, supplier_id, name, price, total_stock, pending_stock 
FROM products
WHERE product_id = ?

I don't want to have to manually run through a DataSet or DataTable to set the values.

I'm sure there's a way to populate the class using some kind of binding / mapping mechanism, but the only stuff I could find was for binding to winforms components or using XAML.

Is there some kind of attribute I can apply to my properties / class to have the class automatically populated from a query row?

like image 295
Polynomial Avatar asked Jul 27 '12 11:07

Polynomial


People also ask

Can we create a table by SQL query result?

If you would like to create a new table, the first step is to use the CREATE TABLE clause and the name of the new table (in our example: gamer ). Then, use the AS keyword and provide a SELECT statement that selects data for the new table.

How do you put query results in a table?

To create an Insert Results queryFrom the Query Designer menu, point to Change Type, and then click Insert Results. In the Choose Target Table for Insert Results Dialog Box, select the table to copy rows to (the destination table).

How do I display SQL results?

You have the option of displaying your query results on the Run SQL window, as opposed to Data Display windows. To do this, go to View > Data Grid (Ctrl+G). Once you have selected this option, a panel will appear at the bottom of the window - your query results will be displayed there.

How do you select data FROM a query?

To select the data that you want to use, you use a select query. A select query is a database object that shows information in Datasheet view. A query does not store data, it displays data that is stored in tables. A query can show data from one or more tables, from other queries, or from a combination of the two.


1 Answers

I've decided to propose another answer, which actually extension to the answer provided by Alex (so all credits to him), but it introduces attributes for the sake of column-name-2-property-name mapping.

First of all custom attribute to hold column name is needed:

[AttributeUsage(AttributeTargets.Property, Inherited = true)]
[Serializable]
public class MappingAttribute : Attribute
{
    public string ColumnName = null;
}

The attribute must be applied to those properties of the class, that are to be populated from database row:

public class Product
{
    [Mapping(ColumnName = "product_id")]
    public int ProductId { get; private set; }

    [Mapping(ColumnName = "supplier_id")]
    public int SupplierId { get; private set; }

    [Mapping(ColumnName = "name")]
    public string Name { get; private set; }
    [Mapping(ColumnName = "price")]
    public decimal Price { get; private set; }
    [Mapping(ColumnName = "total_stock")]
    public int Stock { get; private set; }
    [Mapping(ColumnName = "pending_stock")]
    public int PendingStock { get; private set; }
}

And rest goes as Alex proposed, except that the attribute is used to retrieve column name:

T MapToClass<T>(SqlDataReader reader) where T : class
{
        T returnedObject = Activator.CreateInstance<T>();
        PropertyInfo[] modelProperties = returnedObject.GetType().GetProperties();
        for (int i = 0; i < modelProperties.Length; i++)
        {
            MappingAttribute[] attributes = modelProperties[i].GetCustomAttributes<MappingAttribute>(true).ToArray();

            if (attributes.Length > 0 && attributes[0].ColumnName != null)
                modelProperties[i].SetValue(returnedObject, Convert.ChangeType(reader[attributes[0].ColumnName], modelProperties[i].PropertyType), null);
        }
        return returnedObject;
}
like image 118
Kuba Wyrostek Avatar answered Oct 04 '22 10:10

Kuba Wyrostek