Click here to Skip to main content
15,886,799 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Normally I would use data reader with column index to retrieve data from database but now, i wanted to integrate attribute and use reflection so that i can just loop the properties, as opposed to updating every single connection whenever there are changes on the database. I also thought about using ORM but i just wanted to learn how to use attributes and reflection in this type of scenario.

What I have tried:

Originally I have a class that would set the data from SQL with properties like this:

C#
public class TShirt
{   
public int Id { get; set; }
public string Type { get; set; }
public string Brand { get; set; }

public TShirt()
{

}
public TShirt(int id, string type, string brand)
{
    Id = id;
    Type = type;
    Brand = brand;
}


And i would connect to the database through this code:

C#
public static ArrayList GetTShirt(string itemCategory)
{
ArrayList list = new ArrayList();
string query = string.Format("SELECT * FROM shirt WHERE brand LIKE @brand");

try
{
    conn1.Open();
    command1.CommandText = query;
    command1.Parameters.Add(new SqlParameter("brand", itemCategory));
    SqlDataReader reader = command1.ExecuteReader();

    while (reader.Read())
    {
        int id = reader.GetInt32(0);
        string type = reader.GetString(1);
        string brand = reader.GetString(2);

        TShirt t = new TShirt(id, type, brand);
        list.Add(t);
    }
}
finally
{
    conn1.Close();
    command1.Parameters.Clear();
}

return list;
}


How would you transform this code to integrate attribute and reflection? I've really tried to search online for answers but none of it helps. I also attempted to modify the GetTShirt Method but i just don't have any knowledge about this to base on.
Posted
Updated 2-Jun-17 0:08am

Sounds like you're looking for Dapper[^].
C#
public static IList<TShirt> GetTShirt(string itemCategory)
{
    using (var con = new SqlConnection("..."))
    {
        return con.Query<TShirt>("SELECT * FROM shirt WHERE brand LIKE @brand", new { brand = itemCategory }).ToList();
    }
}

Notes:
Don't store a connection as a class-level field. Create it when needed, and wrap it in a using block. You might want to put the creation in a separate method, and store the connection string in the config file.

Don't use the ArrayList class. Use a generic collection instead.
Generic Collections in the .NET Framework[^]

SELECT * FROM ... is generally a bad idea. You should explicitly state the names of the columns you want to load.
 
Share this answer
 
Comments
BebeSaiyan 5-Jun-17 0:12am    
@Richard Deeming - thanks for the solution but I went to the Entity Framework route.
If I understand what you want correctly.
I've done that once, and you can look at it here[^], but it's a fairly advanced solution using not just reflection but also Expression trees for performance reasons.

But to answer the specifics of your question.
The first parts is to get the properties of the Target class:
C#
Type TShirtType = typeof(TShirt);

And then you can loop the properties using:
C#
foreach (PropertyInfo TShirtMember in TShirtType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
    if (TShirtMember.CanWrite)  // Well you can't map readonly properties

Then you need to compare with the fields in the datareader.
Make an inner loop for the fields:
C#
for (int Ordinal = 0; Ordinal < reader.FieldCount; Ordinal++)

Now you can compare the names:
C#
TShirtMember.Name.ToLower() == reader.GetName(Ordinal).ToLower()

If you have a match you can set the Property:
C#
TargetMember.SetValue(t,reader.Getvalue(Ordinal))
Where t is your TShirt instance
 
Share this answer
 
v2
Comments
Richard Deeming 2-Jun-17 10:51am    
You'll probably want to check whether the property expects any index parameters before trying to write to it.

And you should always normalize strings to upper-case for comparison, to avoid the "Turkish i" problem. But it would be better to use string.Equals(x, y, StringComparison.OrdinalIgnoreCase) to perform a case-insensitive comparison, since that avoids creating a copy of the input strings.
Jörgen Andersson 3-Jun-17 4:45am    
You're quite right, this was a quick writeup to explain the principle.
Good feedback on the comparison, I've never experienced the turkish ı problem.
The question is, what's the best way handle that in SQL? Upper isn't much better since there is a dotted upper case İ as well.
<edit>scrap that, SQL server isn't case sensitive using the default collation.</edit>
BebeSaiyan 5-Jun-17 0:27am    
Thank you for the new insight. Will definitely try this one out.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900