2013-02-13 16 views
5

Sto sviluppando un'API REST utilizzando API Web ASP.NET, Code-First Entity Framework 5 e SQL Server 2012 e devo essere in grado di eseguire la versione dell'API. Ho letto alcuni post e articoli sul blog che indicano la versione dell'API nell'URI o in un'intestazione HTTP personalizzata e utilizzando un parametro IHttpControllerSelector personalizzato per selezionare diversi ApiControllers basati sulla versione indicata. Tutto ciò ha senso.Versioning API con Web API ASP.NET e Entity Framework

Quello che sto cercando di capire è come gestire gli effetti del controllo delle versioni oltre il livello API Web, in particolare in Entity Framework. Come faccio ad evolvere il mio DbContext senza rompere le versioni precedenti dell'API? Posso anche eseguire la versione di DbContext? E se sì, come?

risposta

3

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.

1

Penso che sia una buona pratica per l'evoluzione dell'API Web e del modello DB di sottolineatura separatamente (o modello EF). Ciò significa un modello DTO per l'API Web, che viene mappata al modello EF nell'API Web. Quel livello di riferimento indiretto ti darà la possibilità di apportare modifiche che forse riguardano solo l'API Web o il modello EF. Inoltre, una nuova versione in Web API potrebbe non influire direttamente sul modello EF esistente. Ad esempio, una nuova versione dell'API Web che utilizza un set di tabelle completamente diverso.

Cordiali saluti, Pablo.