数据访问模式:Identity Map(标识映射)模式
1.Identity Map模式简介
Identity Map(标识映射)模式是通过将所有已加载对象放在一个映射中确保所有对象只被加载一次,并且在引用这些对象时使用该映射来查找对象。在处理数据并发访问时,要有一种策略让多个用户共同影响同一个业务实体,这个固然很重要。同样重要的是,单个用户在一个长运行事务或复杂事务中始终使用业务实体的一致版本。Identity Map模式提供的功能;为事务中使用所有的业务对象均保存一个版本,如果一个实体被请求两次,返回同一个实体。
每个业务事务使用一个Identity Map,可以确保如果在同一个事务中两次检索同一个实体,则该实体将是唯一的,而且包含该事务所做的任何修改。
2.Identity Map模式示例
代码结构:
Employee.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DataAccessPatterns.IdentityMapPattern.Model { public class Employee { public Guid ID { get; set; } public string FirstName { get; set; } public string LastName { get; set; } } }
IEmployeeRepository.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DataAccessPatterns.IdentityMapPattern.Model { public interface IEmployeeRepository { Employee FindBy(Guid ID); } }
IdentityMap.cs: 该类使用泛型提供类型安全的Identity Map实现,用于在业务事务期间提供唯一的实体。Identity Map包含一个散列表来存储事务中使用的业务实体,并提供简单的接口来存储和检索实体。
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; namespace DataAccessPatterns.IdentityMapPattern.Repository { public class IdentityMap<T> { Hashtable entities = new Hashtable(); public T GetByID(Guid id) { if (entities.ContainsKey(id)) { return (T)entities[id]; } else { return default(T); } } public void Store(T entity, Guid key) { if (!entities.ContainsKey(key)) { entities.Add(key, entity); } } } }
EmployeeRepository.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using DataAccessPatterns.IdentityMapPattern.Model; namespace DataAccessPatterns.IdentityMapPattern.Repository { public class EmployeeRepository : IEmployeeRepository { private IdentityMap<Employee> _employeeMap; public EmployeeRepository(IdentityMap<Employee> employeeMap) { _employeeMap = employeeMap; } public Employee FindBy(Guid Id) { Employee employee = _employeeMap.GetByID(Id); if (employee == null) { employee = DatastoreFindBy(Id); if (employee != null) { _employeeMap.Store(employee, employee.ID); } } return employee; } private Employee DatastoreFindBy(Guid Id) { Employee employee = default(Employee); // Code to hydrate employee from datastore... return employee; } } }
调用FindBy方法时,Employee Repository首先检查IdentityMap以确定之前是否已经检索Employee实体。如果是,则将其返回给调用者。如果没有,则使用Employee实例的标识从数据存储中查询该实例,然后将其添加到IdentityMap中,如果再次需要从Employee Repository中检索同样的Employee实体,就可以直接使用它。