1

我们有一个场景,我们使用 Enterprise Library Data 包来满足我们的数据访问需求。我们已经实现了一个通用数据阅读器来将我们的数据融合到业务对象中。然而,我们正在寻找一种更有效的方法来做到这一点,这也将满足对象内子集合的深层复制,而无需使用反射,因为我们正在处理大量数据。通用数据阅读器也不能很好地处理大量数据。我知道如果我们使用 EF,它可以解决这个问题,但我们还没有到可以替换整个数据访问层的阶段。是否有替代方案或行业标准来实现这一目标?

4

1 回答 1

4

你为什么不手动编码映射器?这是最快的方法,并且您在项目生命周期中只创建一次映射器,对吗?与您所获得的相比,在生命周期为五年的项目中,所花费的时间可以忽略不计(易于纠正错误,无需解释 OR/M 错误或其“简单性”)。

public interface IEntityMapper
{
   object Map(IDataRecord record);
}

public void UserMapper  : IEntityMapper
{
    public void Map(IDataRecord record)
    {
        var user = new User();
        user.FirstName = record["firstName"]
    }
}

如果您有大量记录,则需要使用number索引器来防止名称查找:

public void UserMapper  : IEntityMapper
{
    public void Map(IDataRecord record)
    {
        var user = new User();

        //requires that you specify columns in your SELECT query
        //to not break the mapper in future versions.
        user.FirstName = record[0]
    }
}

在您的存储库中,您可以这样做:

public class UserRepository
{
    private readonly IDbConnection _connection;
    private UserMapper _mapper = new UserMapper();

    public IReadOnlyList<User> GetAllUsers()
    {
        using (var cmd = _connection.CreateCommand())
        {
            cmd.CommandText = "SELECT Id, UserName FROM Users";
            using (var reader = cmd.ExecuteReader())
            {
                var users = new List<User>();
                while (reader.Read())
                {
                   var user = _mapper.Map(reader);
                   users.Add(user);
                }
                return users;
            }
        }
    }
}

您甚至可以将所有内容移至扩展方法:

public static class CommandExtensions
{
    public static IReadOnlyCollection<T> ToList<T>(this IDbCommand cmd, IDataMapper mapper)
    {
        using (var reader = cmd.ExecuteReader())
        {
            var items = new List<T>();
            while (reader.Read())
            {
               var item= _mapper.Map(reader);
               items.Add(item);
            }
            return item;
        }
    }
}

这为您提供了更轻量级的存储库:

public class UserRepository
{
    private readonly IDbConnection _connection;
    private UserMapper _mapper = new UserMapper();

    public IReadOnlyList<User> GetAllUsers()
    {
        using (var cmd = _connection.CreateCommand())
        {
            cmd.CommandText = "SELECT Id, UserName FROM Users";
            return cmd.ToList<User>(_mapper);
        }
    }
}

深拷贝

关于深拷贝,我试图避免使用复杂的实体(除非子实体实际上是值对象)。最好使用 ID 来引用其他实体,因为否则很难在代码中的某个位置保留对实体的责任。

当谈到映射时,我可能会引入一个约定,在映射接口中使用另一种方法映射子对象:

public interface IEntityMapper
{
   object Map(IDataRecord record);
   object Map(IDataRecord record, string prefix);
}

前缀可以用作约定来指示使用连接从多个表中获取信息。

public void UserMapper  : IEntityMapper
{
    private AddressMapper _childMapper = new AddressMapper();

    public void Map(IDataRecord record)
    {
        var user = new User();
        user.FirstName = record["FirstName"]
        user.Address = _childMapper.Map(record, "Address_");
    }
}

..这将使您的存储库方法如下所示:

public class UserRepository
{
    private readonly IDbConnection _connection;
    private UserMapper _mapper = new UserMapper();

    public IReadOnlyList<User> GetAllUsers()
    {
        using (var cmd = _connection.CreateCommand())
        {
            cmd.CommandText = @"SELECT Id, UserName, Address.City as Address_City 
                                FROM Users 
                                JOIN Address ON (Address.Id = Users.AddressId)";
            return cmd.ToList<User>(_mapper);
        }
    }
}

我写过关于 ADO.NET 和(我的)最佳实践的文章:http: //blog.gauffin.org/2013/01/04/ado-net-the-right-way/

于 2015-10-19T11:56:45.927 回答