HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Using Custom Attributes to Populate Members from IDataReader

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
idatareadercustomattributespopulateusingmembersfrom

Problem

Just learned how to use custom attributes in C# and the first useful thing I did with it was to make a class object representing a database table. The constructor can accept an IDataReader and populate the members based on the custom attribute. Is this a good usage of custom attributes?

[AttributeUsage(AttributeTargets.Property)]
public class DatabaseField: Attribute
{
    public string Name { get; set; }
    public DatabaseField( string name )
    {
        Name = name;
    }
}

public class Employee
{
    [DatabaseField("Employee_ID")]
    public string EmployeeId { get; set; }

    [DatabaseField("LogonId")]
    public string Username { get; set; }

    [DatabaseField("Email")]
    public string EmailAddress { get; set; }

    [DatabaseField("NAME")]
    public string DisplayName { get; set; }

    [DatabaseField("First_Name")]
    public string FirstName { get; set; }

    [DatabaseField("Middle_Name")]
    public string MiddeName { get; set; }

    [DatabaseField("Last_Name")]
    public string LastName { get; set; }

    [DatabaseField("Name_Suffix")]
    public string NameSuffix { get; set; }

    [DatabaseField("Job_Title")]
    public string JobTitle { get; set; }

    [DatabaseField("Department")]
    public string Department { get; set; }

    [DatabaseField("Emp_Type")]
    public string EmployeeType { get; set; }

    [DatabaseField("SupervisorID")]
    public string ManagerId { get; set; }

    public Employee( IDataReader reader )
    {
        foreach( PropertyInfo prop in typeof(Employee).GetProperties() )
        {
            foreach( object attr in prop.GetCustomAttributes(true) )
            {
                DatabaseField field = attr as DatabaseField;
                if( null != field )
                {
                    object value = reader[field.Name];
                    prop.SetValue(this, value == DBNull.Value ? null : value, null);
                }
            }
        }
    }
}

Solution

public class DatabaseField: Attribute


According to the naming guidelines, the names of attribute classes should end with Attribute, so this class should be called DatabaseFieldAttribute.

public string Name { get; set; }


I don't see any reason why the setter should be public, so I would make it private.

public Employee( IDataReader reader )


I don't think all this code should be here. Instead, it should be in a library that's not specific to your types.

Have you considered adding the knowledge of your naming conventions to your code, so that not all properties need the attribute?

Also, I would go the other way around: for each column in the reader, find the appropriate property to set. That way, if your type is missing a property, you can learn about it.

foreach( object attr in prop.GetCustomAttributes(true) )


I would use the generic extension method GetCustomAttribute() here, to simplify your code:

var attr = prop.GetCustomAttribute(true);


if( null != field )


There is not reason to use Yoda conditions in C#. The issue they're addressing is that buggy code like if (field = null) is valid C and C++. But it's not valid C#.

Code Snippets

public class DatabaseField: Attribute
public string Name { get; set; }
public Employee( IDataReader reader )
foreach( object attr in prop.GetCustomAttributes(true) )
var attr = prop.GetCustomAttribute<DatabaseFieldAttribute>(true);

Context

StackExchange Code Review Q#66388, answer score: 5

Revisions (0)

No revisions yet.