有没有一种通用方法来填充数据库中的对象

本文关键字:填充 数据库 对象 方法 一种 有没有 | 更新日期: 2023-09-27 18:36:45

在我的软件中有一种常见的模式,其中完成数据库查询并从该查询创建对象列表,其中对象是从SqlDataReader构造的。

例如:

public List<Authorization> ReadAuthorizations() {
  List<Authorization> authorizations = new List<Authorization>();
  using (SqlConnection connection = GetConnection(mConnString)) {
    using (SqlDataReader authReader = CmdFactory.Instance.ReadAuthorizations(connection))                                   {
      while (authReader.Read()) {
        Authorization auth = new Authorization(authReader);
        authorizations.Add(auth);
      }
    }
 }
 return authorizations;
}

您可以将Authorization替换为任何类型的对象,但每次的模式都相同。唯一的变量是对象类型和用于查询数据库的函数。

List<Authorization> ReadAuthorizations()
List<Login> ReadLogins()
List<Batch> ReadBatches()
// etc

现在我认为这只是对通用函数的尖叫,我想出了这个:

public List<T> Read<T>(Func<SqlConnection, SqlDataReader> func) where T : new()
{
    List<T> objects = new List<T>();
    using (SqlConnection connection = GetConnection(_ropsString))
    {
        using (SqlDataReader reader = func(connection))
        {
            while (reader.Read())
            {
                T obj = new T(reader);
                objects.Add(obj);
            }
        }
    }
    return objects;
}

这几乎有效,除了要构造的对象不允许采用参数,VS2k10 说:

"T":创建变量类型的实例时无法提供参数

有没有办法解决这个问题,以便变量类型可以获取构造函数参数?

有没有一种通用方法来填充数据库中的对象

有很多方法可以给这只猫剥皮,但要让你沿着你选择探索的方向前进:

使用泛型约束指定where T : IPopulateFromReader, new()并将 reader 参数移动到方法调用中:

T obj = new T();
obj.PopulateFromReader(reader);
objects.Add(obj);
interface IPopulateFromReader
{
    void PopulateFromReader(IDataReader reader);
}

更严肃地说,也许看看ORM解决方案,例如:

  • 冬眠
  • 实体框架
  • Dapper(荣誉奖,用于SO)

这样的例子不胜枚举。关键是,它们成功地提供了对数据库访问的抽象并缓解了阻抗不匹配问题,使您可以专注于域模型和业务逻辑,而忽略样板 DAL 代码。通常还支持管理数据库模式(尽管对此的支持因库/框架的重点而异)。

我知道

这不是最漂亮的方法,但是您可以放置一个接口约束,然后尝试将读取器作为属性(或构造方法)传递给构造的对象。

T obj = new T();
obj.Reader = reader;
objects.Add(obj);

我会重新建议Dapper:我一直用它来做这种工作:

衣冠楚楚

    public class Dog
    {
        public int? Age { get; set; }
        public Guid Id { get; set; }
        public string Name { get; set; }
        public float? Weight { get; set; }
        public int IgnoredProperty { get { return 1; } }
    }            
    var guid = Guid.NewGuid();
    var dogs = connection.Query<Dog>("select Age = @Age, Id = @Id", new { Age = (int?)null, Id = guid });
    dogs.Count()
        .IsEqualTo(1);
    dogs.First().Age
        .IsNull();
    dogs.First().Id
       .IsEqualTo(guid);