Looking for a way to retrieve attribute data for a property on a class (many different types) in my data layer with an extension method...
Final goal is to see the method here and be able to access the properties:
I would expect to be able to do something like (non-working code):
Customer c = new Customer();
int mcl = c.CustNo.GetSchemaDetails().MaxCharLength;
The attribute is assigned to the class property as such:
public class Customer
{
[ColumnSchema("Customer", "CUST_NO")]
public string CustNo { get; set; }
//...
}
I've created an extension method to retrieve the 'SchemaDetails' object from the 'ColumnSchemaAttribute'
public class AttributeExtensions
{
public static SchemaDetails GetSchemaDetails(Type T)
{
ColumnSchemaAttribute csa = (ColumnSchemaAttribute)Attribute.GetCustomAttribute(T, typeof(ColumnSchemaAttribute));
return csa.SchemaDetails;
}
}
Bulk of the 'ColumnSchemaAttribute' which returns db schema details for the column
public class ColumnSchemaAttribute : System.Attribute
{
private string tableName, columnName;
public ColumnSchemaAttribute(string TableName, string ColumnName)
{
tableName = TableName;
columnName = ColumnName;
}
private SchemaDetails schemaDetails;
public SchemaDetails SchemaDetails
{
get
{
if (schemaDetails == null) { schemaDetails = getSchemaDetails(); }
return schemaDetails;
}
}
private SchemaDetails getSchemaDetails()
{
SchemaDetails sd = null;
string sql =
@"
SELECT * FROM INFORMATION_SCHEMA.COLUMNS c
LEFT JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE ccu ON ccu.COLUMN_NAME = c.COLUMN_NAME and ccu.TABLE_NAME = c.TABLE_NAME
LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc ON tc.CONSTRAINT_NAME = ccu.CONSTRAINT_NAME and tc.TABLE_NAME = ccu.TABLE_NAME
WHERE c.TABLE_NAME = @TableName and c.COLUMN_NAME = @ColumnName
";
try
{
using (SqlConnection sqlConnection = new SqlConnection(Helper.GetConnectionString()))
{
sqlConnection.Open();
using (SqlCommand sqlCommand = new SqlCommand(sql, sqlConnection))
{
sqlCommand.CommandType = CommandType.Text;
sqlCommand.Parameters.Add("@TableName", SqlDbType.NVarChar, -1).Value = tableName;
sqlCommand.Parameters.Add("@ColumnName", SqlDbType.NVarChar, -1).Value = columnName;
SqlDataReader sqlDataReader = sqlCommand.ExecuteReader();
while (sqlDataReader.Read())
{
sd = readData(sqlDataReader);
}
}
}
}
catch (Exception ex)
{
throw new System.ArgumentException(ex.Message);
}
return sd;
}
}
Any help regarding a way to do this or an alternative approach is very much appreciated.
CodePudding user response:
In order to getting any property attribute you need the retrieve the property info not the type, one way to do this is using expressions, next step after retrieving the SchemaDetails
instance value would be to get some property value from it:
public static class AttributeExtensions
{
public static SchemaDetails GetSchemaDetails<T>(this T _, Expression<Func<T, object>> propertyAccessorExpression)
{
if (propertyAccessorExpression.Body is MemberExpression memberExpression)
{
if (memberExpression.Member is PropertyInfo propertyInfo)
{
var attribute = propertyInfo.GetCustomAttribute<ColumnSchemaAttribute>();
if (attribute != null)
{
return attribute.SchemaDetails;
}
}
}
return default;
}
}
usage:
public static void Main()
{
var customer = new Customer();
var length = customer
.GetSchemaDetailsFor(x => x.CustNo)
.MaxCharLength;
Console.WriteLine(length);
}