То, что я закончил, было комбинацией шаблона репозитория с ответом Пабло. Суть в том, что мои модели 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.