【问题标题】:how to return a loosely-typed object?如何返回一个松散类型的对象?
【发布时间】:2017-12-20 20:10:26
【问题描述】:

当数据库架构发生变化时,我们如何避免破坏控制器方法的变化?

假设我要返回一个对象:

public class Bike
{
   public int Wheels {get;}
   public int Id {get;}
}

在以下控制器中:

public class BikeController
{
    [HttpGet]
    public List<Bike> Get([FromBody] MyRequest request)
    {
        var context = new DbContext(_repository.Database.Connection.ConnectionString);
        var procedure = request;
        return context.Database.ExecuteStoredProcedure<Bike>(procedure).ToList();
    }
}

在某些时候,数据库代码会发生变化。 我不想在 C# 中重新定义 Bike 架构。

我们如何更改 Bike 控制器方法的签名,以便在数据库架构更改时不发生任何重大更改?

我正在寻找类似以下的内容:

public IHttpActionResult Get()
{
    var context = new DbContext(_repository.Database.Connection.ConnectionString);
    var procedure = request;
    return context.Database.ExecuteStoredProcedure<object>(procedure).ToList();
}

【问题讨论】:

  • 您是否担心控制器方法会中断,或者您是否担心如果返回的对象发生更改,API 的客户端可能会中断?
  • @ScottHannen 感谢您的回复。我不清楚,我已经更新了问题。我担心开发人员必须更新模型以反映数据库模式的变化,我不想这样做而是返回一个弱类型的对象
  • 取决于客户端如何使用您的 api。假设您将对象作为 json 返回 - 大多数客户不会关心其他字段,并且它不太可能破坏任何内容。如果您删除字段 - 这当然是重大变化。
  • @Evk 我根本不想返回 Bike,我想返回动态或对象或抽象的东西,这可能吗?>
  • 我怀疑他正在调用 .ToList 因为他正在返回 List<...> 将您的返回类型更改为 IEnumerable<...> 那么您将不需要 .ToList。

标签: c# .net asp.net-web-api asp.net-web-api2 visual-studio-2017


【解决方案1】:

我不明白为什么您的控制器根本需要更改,因为您只是直接返回检索到的类型,而没有在您的操作方法中引用它的任何属性。

此外,为什么在返回单个 Bike 对象时调用 .ToList()。此外,您可以考虑使用 Model 或 ViewModel 而不是直接返回实体作为选项。

@Evk 已经指出,一个新添加的属性在反序列化时会丢失,但如果你想返回一个抽象对象,那么你可以让你的所有实体继承自 BaseEntity 具有公共属性并返回它而不是像

BaseEntity obj = context.Database.ExecuteStoredProcedure<Bike>(procedure);
returb obj;

【讨论】:

  • 但不会中断:return context.Database.ExecuteStoredProcedure(procedure).ToList(); ??
  • @l--''''''------'''''''''''',为什么?如果您的数据库架构发生变化,那么无论如何您都必须刷新您的应用程序架构......希望您使用的是 EF
  • 不,我直接进入数据库,我不想重新编译我的代码
  • @l--''''''---------''''''''''''',从那以后就不可能了不会反映实际的架构更改。如果您真的想要,请尝试使用Expando 对象
  • 看来我的建议绝对不是解决问题的标准方法,但令我惊讶的是,没有更多关于如何创建不关心的 READONLY 控制器方法的信息输入它正在返回的类型并简单地从数据库中返回 json
【解决方案2】:

我认为你有几个选择:

  1. 返回 dynamic 而不是 Bike。但是,这会对dynamic 对象的所有用户的性能产生影响。

  2. 返回object 而不是Bike

但在这两种情况下,您的 Bike 存储过程仍将返回与 Bike 对象不兼容的更新数据,因此您仍需要重新编译控制器。

  1. 返回代表BikeController 响应并匹配存储过程响应的标准对象。

考虑您如何在 SQL 中处理数据库更新 - 您的 SELECT 语句指定您需要的确切列,并且不受不影响返回列的架构更改的影响,或者如果您使用*,则忽略您不使用的任何列'不需要,这不利于强类型或 ORM。

【讨论】:

    【解决方案3】:

    您只是从数据库中检索一个对象,对象内部的属性数量不会影响或破坏您的 ActionMethod。

    如果您仍然担心对象内部的属性不是您想要在视图上呈现的内容,那么您可以使用 ViewModel 并使用您的 Bike 对象属性来填充视图模型并呈现视图模型。

    【讨论】:

    • 如果数据库将为 Bike 返回一个额外的字段,那么 context.Database.ExecuteStoredProcedure(procedure);不会显示那个字段,对吧?
    • @l--''''''---------'''''''''''' 取决于你的 SP 正在做什么,如果是的话只需选择特定 id 的所有值,然后它将返回该 id 的所有值。
    • 当您对数据库进行更改时,例如您将另一个字段添加到自行车表中,那么您必须更新您的 edmx 文件,一旦您更新了 edmx 文件,您的模型就是 Bike 类在c#中将由实体框架更新
    • 不,如果该字段未在 Bike 中定义,则不会返回该字段
    • @l--''''''---------'''''''''''' 如果您使用的是实体框架,那么您不必自己定义新字段,当您更新 edmx 文件时,新字段将通过实体框架添加到您的 Bike 类中
    【解决方案4】:

    只要您不访问任何属性或使用任何方法,它的存在就取决于模式对象或与数据库相关的任何内容,您是安全的。 使控制器与数据库模式无关,这将使该控制器不太可能由于数据库端的更改而被更改,这就是创建Data Access layers 的原因。 我认为如果我们应用关注点分离原则,我们会发现处理数据库不是Controller 的责任,这必须通过某些Brokers 来完成,例如注入控制器构造函数的存储库接口类型。控制器只会看到插入、更新、删除方法,但它对数据库一无所知。 此外,它不是一个松散类型的对象。这是您真正需要的松散耦合类型。

    【讨论】:

    • 我不同意你最后的说法
    • 为什么?这不是松散类型的吗?您不想使用以Strongly typed 语言为特征的语言创建松散类型的对象。
    • 您没有访问任何属性或使用任何依赖于数据库的method/property 对吗?那么,就不需要创建弱类型对象了!
    • 我同意这是糟糕的设计,但老板就是老板
    • 哦,我明白了!你一定处于非常艰难的境地。我讨厌教条主义的老板!
    猜你喜欢
    • 1970-01-01
    • 2019-08-01
    • 2014-02-14
    • 2020-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-31
    • 1970-01-01
    相关资源
    最近更新 更多