C#中的自定义属性用于数据类型



我正在考虑制作自定义属性,以便当我们在不同对象/表上使用多个数据读取器[SqldataReader]时,我们可以使用属性来获取属性的类型,以及该属性的" columnName"。这样,我们就可以使用一种将数据读取器作为param的方法,从那里可以反映要在列中读取的属性。当前正在完成的工作的一个示例是下面,然后是我要完成的工作的示例。我遇到的问题是如何管理如何告诉它(类型)是什么。

 private static App GetAppInfo(SqlDataReader dr)
    {
        App app = new App();
        app.ID = MCCDBUtility.GetDBValueInt(dr, "APPLICATION_ID");
        app.Name = MCCDBUtility.GetDBValueString(dr, "APPNAME");
        app.Desc = MCCDBUtility.GetDBValueString(dr, "APPDESCRIPTION");
        app.Version = MCCDBUtility.GetDBValueString(dr, "APP_VERSION");
        app.Type = MCCDBUtility.GetDBValueString(dr, "APPLICATIONTYPEID");
        app.AreaName = MCCDBUtility.GetDBValueString(dr, "AREANAME");
        return app;
    }

我在想什么,所以如果我有这样的课,例如:

[DataReaderHelper("MethodNameToGetType", "ColumnName")]
public string APPNAME {get;set;}

我该怎么做?

所有拳头,这是可能的,如果您喜欢,我可以添加代码示例。但是:这不是一个好主意。

为什么,你问?

首先 - datareader为您提供一个方法getsematable(),该方法包含一个属性DataType,该属性是System.Type对象。因此,基本上,您可以创建一个为您的逻辑的MCCDBUtility.GetValue(dr, "columnName")

秒 - 您对象上有一个int属性,但是您的数据标准返回小数。对于这种情况,您可以使用Convert.ChangeType(value, type)

如果结合了可以实现想要的东西

instance.Id = MCCDBUtility.GetValue<int>(dr, "columnName")
public T GetValue<T>(IDataReader reader, string columnName)
{
     object value GetValue(reader, columnName);
     return Convert.ChangeType(value, typeof(T));
}
private object GetValue(IDataReader reader, string columnName)
{
    var schmema = reader.GetSchemaTable();
    var dbType = typeof(object);
    foreach(DataRowView row in schema.DefaultView)
        if (row["columnName"].ToString().Equals(columnName, StringComparer.OrdinalIgnoreCase))
            return row["ColumnType"];
    if (dbType.Equals(typeof(int))
        return GetInt(reader, columnName)
    ... // you get the point
    else
        return GetObject(reader, columnName);
}

和第三 - 无论如何都不要这样做,可以将查询映射到业务对象上。我不想给它们命名,但非常轻巧且易于理解的是Dapper.NET,请尝试一下。https://github.com/stackexchange/dapper-dot-net

与https://github.com/tmsmith/dapper-extensions结合使用,您可以轻松地将数据库查询映射到Pocos

update

如所承诺的,这是自行实施的代码。只需创建一个Visual Studio测试项目,插入代码并让其运行即可。为了读取,我省略了未使用的IREADREADREADER接口实现,因此您必须让Intellisense为您创建它们。

进行测试并享受。

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        var values = new Dictionary<string, object>();
        values.Add("ProductId", 17);
        values.Add("ProductName", "Something");
        values.Add("Price", 29.99M);
        var reader = new FakeDataReader(values);
        var product1 = new Product();
        reader.SetValue(product1, p => p.Id);
        reader.SetValue(product1, p => p.Name);
        reader.SetValue(product1, p => p.Price);
        Assert.AreEqual(17, product1.Id);
        Assert.AreEqual("Something", product1.Name);
        Assert.AreEqual(29.99M, product1.Price);
        var product2 = new Product();
        reader.SetAllValues(product2);
        Assert.AreEqual(17, product2.Id);
        Assert.AreEqual("Something", product2.Name);
        Assert.AreEqual(29.99M, product2.Price);
    }
}
public class Product
{
    [Mapping("ProductId")]
    public int Id { get; set; }
    [Mapping("ProductName")]
    public string Name { get; set; }
    public decimal Price { get; set; }
}
[AttributeUsage(AttributeTargets.Property, AllowMultiple=false)]
public class MappingAttribute : Attribute
{
    public MappingAttribute(string columnName)
    {
        this.ColumnName = columnName;
    }
    public string ColumnName { get; private set; }
}
public static class IDataReaderExtensions
{
    public static void SetAllValues(this IDataReader reader, object source)
    {
        foreach (var prop in source.GetType().GetProperties())
        {
            SetValue(reader, source, prop);
        }
    }
    public static void SetValue<T, P>(this IDataReader reader, T source, Expression<Func<T, P>> pe)
    {
        var property = (PropertyInfo)((MemberExpression)pe.Body).Member;
        SetValue(reader, source, property);
    }
    private static void SetValue(IDataReader reader, object source, PropertyInfo property)
    {
        string propertyName = property.Name;
        var columnName = propertyName;
        var mapping = property.GetAttribute<MappingAttribute>();
        if (mapping != null) columnName = mapping.ColumnName;
        var value = reader.GetValue(reader.GetOrdinal(columnName));
        var value2 = Convert.ChangeType(value, property.PropertyType);
        property.SetValue(source, value2, null);
    }
}
public static class ICustomFormatProviderExtensions
{
    public static T GetAttribute<T>(this ICustomAttributeProvider provider)
    {
        return (T)provider.GetCustomAttributes(typeof(T), true).FirstOrDefault();
    }
}
public class FakeDataReader : IDataReader
{
    private Dictionary<string, object> values;
    public FakeDataReader(Dictionary<string, object> values)
    {
        this.values = values;
    }
    public int GetOrdinal(string name)
    {
        int i = 0;
        foreach (var key in values.Keys)
        {
            if (key.Equals(name, StringComparison.OrdinalIgnoreCase)) return i;
            i++;
        }
        return -1;
    }
    public object GetValue(int i)
    {
        return values.Values.ToArray()[i];
    }
}

最新更新