我最终做的是将存储库模式与 Pablo 的答案结合起来。它的要点是我的 EF 模型是版本化的,我使用 EF Code-First Migrations 将数据库迁移到模型的新版本,我DbContext
总是使用最新版本的模型,我开发了许多具体的存储库每个都实现IRepository<TItem>
下面的接口。
public interface IRepository<TItem> : IQueryable<TItem>, ICollection<TItem>, IDisposable
where TItem : class
{
void Update(TItem item);
void SaveChanges();
}
一种实现IRepository<TItem>
是DbRepository<TItem>
包装用于与数据库对话的实体框架代码。
public class DbRepository<TItem> : IRepository<TItem>
where TItem : class
{
private MyDbContext _db;
public DbRepository()
{
_db = new MyDbContext();
}
// Implementation of IRepository<TItem> methods
}
另一个实现IRepository<TItem>
是TypeConversionRepository<TExternal,TInternal>
一个抽象类,它有助于从一种模型类型转换为另一种模型类型。
public abstract class TypeConversionRepository<TExternal, TInternal> : IRepository<TExternal>
where TExternal : class
where TInternal : class
{
protected IRepository<TInternal> InternalRepository { get; set; }
protected abstract TInternal ConvertInbound(TExternal externalItem);
protected abstract TExternal ConvertOutbound(TInternal internalItem);
// Implementation of IRepository<TItem> methods
}
返回模型或接受模型作为参数的方法使用ConvertInbound()
和ConvertOutbound()
转换类型的模型,TExternal
反之亦然TInternal
。因此,给定以下 2 个版本MyModel
,我们可以编写 2 个版本的 MyModelRepository;版本 2 可以直接与数据库对话,而版本 1 需要从版本 2 转换回版本 1。
namespace Models.v1
{
public class MyModel
{
public int Id { get; set; }
public string MyProperty { get; set; }
}
public class MyModelRepository : TypeConversionRepository<Models.v1.MyModel,Models.v2.MyModel>
{
MyModelRepository()
{
this.InternalRepository = new Models.v2.MyModelRepository();
}
protected override TInternal ConvertInbound(TExternal externalItem)
{
return new Models.v2.MyModel
{
Id = externalItem.Id,
MyNewProperty = externalItem.MyProperty
};
}
protected override TExternal ConvertOutbound(TInternal internalItem)
{
return new Models.v1.MyModel
{
Id = internalItem.Id,
MyProperty = internalItem.MyNewProperty
};
}
}
}
namespace Models.v2
{
public class MyModel
{
public int Id { get; set; }
public string MyNewProperty { get; set; }
}
public class MyModelRepository : DbRepository<MyModel>
{
}
}
现在 v1 ApiController 可以使用 v1 MyModelRepository,v2 ApiController 可以使用 v2 MyModelRepository,但最终所有请求都使用已迁移到 v2 的数据库。