直接使用 EF ObjectContext + LINQ to Entities 雖簡單,但導致:
where e.Age >= 60),需求變更須改模型。倉儲模式解耦領域與基礎設施,引入 Specification 模式(以 Func<T, bool> 為輕量規約)解決查詢硬編碼。
public interface IRepository<TEntity> where TEntity : EntityObject, IAggregateRoot {
void Add(TEntity entity);
TEntity GetByKey(int id);
IEnumerable<TEntity> FindBySpecification(Func<TEntity, bool> spec);
void Remove(TEntity entity);
void Update(TEntity entity);
}
泛型約束限定為聚合根實體。介面置於領域層,不依賴具體實現。
internal class EdmRepository<TEntity> : IRepository<TEntity> where TEntity : EntityObject, IAggregateRoot {
readonly ObjectContext _ctx;
readonly string _entitySetName;
public EdmRepository(ObjectContext ctx) {
_ctx = ctx;
var attr = (AggregateRootAttribute)typeof(TEntity)
.GetCustomAttributes(typeof(AggregateRootAttribute), true)[0];
_entitySetName = attr.EntitySetName;
}
public void Add(TEntity e) => _ctx.AddObject(_entitySetName, e);
public TEntity GetByKey(int id) {
var sql = $"SELECT VALUE ent FROM {_entitySetName} AS ent WHERE ent.Id=@id";
var q = _ctx.CreateQuery<TEntity>(sql, new ObjectParameter("id", id));
return q.FirstOrDefault() ?? throw new Exception("Not found");
}
public void Remove(TEntity e) => _ctx.DeleteObject(e);
public void Update(TEntity e) { /* TODO */ }
public IEnumerable<TEntity> FindBySpecification(Func<TEntity, bool> spec)
=> throw new NotImplementedException(); // 後續用 Specification 替換
}
聚合根以 [AggregateRoot("EntitySetName")] 標記,實現體透過反射讀取 EntitySetName。
配置 ObjectContext、EdmRepository<Customer>,建構子注入 ObjectContext。測試代碼驗證倉儲操作完全不感知 EF 細節。

事務處理上下文、可擴展倉儲框架、Specification 完整實作。