Quello che ho finito è stato combinare il modello di deposito con la risposta di Pablo. Il nocciolo della questione è che i miei modelli EF sono versionati, io uso EF Code-First Migrations per migrare il database alle nuove versioni dei modelli, il mio DbContext
funziona sempre con l'ultima versione dei modelli, ho sviluppato un certo numero di repository concreti che ciascuno implementa l'interfaccia IRepository<TItem>
qui sotto.
public interface IRepository<TItem> : IQueryable<TItem>, ICollection<TItem>, IDisposable
where TItem : class
{
void Update(TItem item);
void SaveChanges();
}
Un'implementazione di IRepository<TItem>
è DbRepository<TItem>
che avvolge il codice di Entity Framework utilizzato per comunicare con il database.
public class DbRepository<TItem> : IRepository<TItem>
where TItem : class
{
private MyDbContext _db;
public DbRepository()
{
_db = new MyDbContext();
}
// Implementation of IRepository<TItem> methods
}
Un'altra implementazione di IRepository<TItem>
è TypeConversionRepository<TExternal,TInternal>
che è una classe astratta che facilita la conversione da un tipo ad un altro modello.
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
}
metodi che restituiscono modelli o accettare modelli come parametri utilizzano ConvertInbound()
e ConvertOutbound()
convertire modelli di tipo TExternal
per TInternal
e viceversa. Pertanto, date le seguenti 2 versioni di MyModel
, possiamo scrivere 2 versioni di MyModelRepository; Versione 2 può parlare direttamente al database mentre la versione 1 sarà necessario convertire dalla versione 2 di nuovo alla versione 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>
{
}
}
Ora l'ApiController v1 può utilizzare la MyModelRepository v1, v2 l'ApiController può utilizzare la MyModelRepository v2, ma alla fine tutte le richieste utilizzano un database che è stato migrato alla v2.