7

我正在使用 ASP.NET Web API、Code-First Entity Framework 5 和 SQL Server 2012 开发 REST API,我需要能够对 API 进行版本控制。我已经阅读了一些关于在 URI 或自定义 HTTP 标头中指示 API 版本以及使用自定义 IHttpControllerSelector 根据指示版本选择不同 ApiController 的博客文章和文章。这一切都说得通。

我正在努力弄清楚的是如何管理 Web API 层之外的版本控制的影响,特别是在实体框架中。如何在不破坏旧版本 API 的情况下改进我的 DbContext?我也可以对 DbContext 进行版本控制吗?如果是这样,怎么办?

4

2 回答 2

4

我最终做的是将存储库模式与 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 的数据库。

于 2013-03-11T14:35:43.843 回答
1

我认为分别发展 Web API 和下划线 DB 模型(或 EF 模型)是一个很好的做法。这意味着 Web API 的 DTO 模型,它映射到 Web API 中的 EF 模型。该间接层将使您有机会进行可能仅影响 Web API 或 EF 模型的更改。此外,Web API 中的新版本可能不会直接影响现有的 EF 模型。例如,使用一组完全不同的表的新版本的 Web API。

问候,巴勃罗。

于 2013-03-08T13:58:16.900 回答