Don*_*nny 2 c# performance entity-framework data-access-layer idatareader
我们有一个场景,我们使用 Enterprise Library Data 包来满足我们的数据访问需求。我们实现了一个通用数据读取器来将我们的数据合并到业务对象中。然而,我们正在寻找一种更有效的方法来做到这一点,这也将满足对象内子集合的深度复制,而无需使用反射,因为我们正在处理大量数据。通用数据读取器在处理大量数据时也表现不佳。我知道如果我们使用 EF,它可以解决这个问题,但我们还没有达到可以替换整个数据访问层的阶段。是否有替代方案或行业标准来实现这一目标?
为什么不手动编写映射器代码?这是最快的方法,并且在项目生命周期内只创建一次映射器,对吧?在寿命为五年十年的项目中,与您获得的时间相比,所花费的时间可以忽略不计(易于纠正错误,无需解释 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"]
}
}
Run Code Online (Sandbox Code Playgroud)
如果您有大量记录,则需要使用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]
}
}
Run Code Online (Sandbox Code Playgroud)
在您的存储库中,您可以这样做:
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;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
您甚至可以将所有内容移至扩展方法:
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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
这为您提供了更轻量级的存储库:
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
深拷贝
关于深层副本,我试图避免使用复杂的实体(除非子实体实际上是值对象)。最好使用 ID 来引用其他实体,否则很难将实体的责任保留在代码中的一处。
当谈到映射时,我可能会引入一个约定,其中使用映射接口中的替代方法来映射子对象:
public interface IEntityMapper
{
object Map(IDataRecord record);
object Map(IDataRecord record, string prefix);
}
Run Code Online (Sandbox Code Playgroud)
前缀可以用作约定来指示使用联接从多个表中获取信息。
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_");
}
}
Run Code Online (Sandbox Code Playgroud)
..这将使您的存储库方法如下所示:
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我写过有关 ADO.NET 和(我的)最佳实践的文章:http://blog.gauffin.org/2013/01/04/ado-net-the-right-way/
| 归档时间: |
|
| 查看次数: |
3950 次 |
| 最近记录: |