【问题标题】:Saving OData entities from api with id to database in entity framework将 OData 实体从具有 id 的 api 保存到实体框架中的数据库
【发布时间】:2016-10-19 22:32:26
【问题描述】:

我有多个项目通过 API 端点返回相同的 OData 实体。现在我想调用所有项目并将它们存储在带有实体框架的调用项目数据库中。

要将它们添加到数据库中,ID 会被覆盖,但我也想保存实体在项目数据库中的 ID。所以如果需要我仍然可以访问它们并检查数据是否已经在我的数据库中。因此,我需要向实体添加另一个 MainProjectID 和 projectID 列。

我尝试创建一个新类,该类引用了我要保存的实体,但这使用了实体的新 ID。我也尝试过继承该类,但这给了我关键的冲突问题,并且泛型在实体框架中也不起作用(我不是说它们应该)。所以我现在有点不知所措。

我基本上想将 id 保存为非键。有什么办法可以在不编写全新的类并手动解析它们的情况下做到这一点?

任何帮助将不胜感激。

【问题讨论】:

  • “覆盖”是指在 DB 上它们被处理为 auto_increment 列并且原始值丢失了吗?如果是这样,请看一下:stackoverflow.com/questions/7206273/…
  • 是的,但我仍然不能使用 id 的原始值作为键,因为它们可能在项目之间相互冲突。因为它们并非都来自相同的 dB。而且由于实体基本上都将被放入同一个表中,因此 id 将发生冲突。
  • 那既然你尝试了继承和引用,我猜你不能修改实体类?
  • 如有必要,我可以,但我宁愿不仅为聚合添加任何值。因为这对我来说似乎是糟糕的设计(仅为聚合添加字段)。但如有必要,这是可能的。
  • 我正在考虑可能将 id 和 projectname 一起用作主键。然后像你说的那样关闭自动增量。我明天试试。

标签: c# asp.net entity-framework asp.net-web-api2 odata


【解决方案1】:

我们有多种选择:

  • 在分布式系统中,处理此类 ID 冲突的最佳方法是使 ID 全局唯一。如果您可以修改 ID 的生成方式,那将是我的选择。您可以使用将生成通用唯一标识符的 UUID(或 Microsoft 实施 GUID)。或者,如果这看起来有点矫枉过正,您可以设计一个简单的机制,将 ID 与 projectID 结合起来。但是,您应该确保您将使用的方法不会产生任何冲突(没有两个不同的 id-projectId 对将映射到相同的值)。

    这将确保在整个应用程序中使用相同的实体,并且如果您尝试将来自不同来源的记录放入同一个表中,则不会发生重叠。您只需要实现一种机制来记录哪个 ID 来自哪个来源。为此,您可以在聚合器中使用参考实体。您还需要禁用 ID 列的自动递增特性,以便在表中使用您的全局唯一值。

  • 您可以使用不同的实体来生成和聚合应用程序。我不知道您的应用程序,但这对我来说似乎是一种不错的方法,因为聚合应用程序对实体有不同的想法。聚合应用程序关心哪个应用程序生成了实体,这可能使将源应用程序标识符放入条目中是合理的。您的实体只会有所不同,当您从 API 接收 OData 对象时,您需要复制所有其他属性并自己放置项目标识符。

  • 您可以使用以前的解决方案,但您可以使用派生类以避免重复您的对象属性。这是一个更好的设计替代方案。但是,使用这种方法,主键会出现一些问题(正如您所说的那样)。考虑这个例子

    public class Base {
        public int ID { get; set; }
    
        [Required]
        [StringLength(50)]
        [Display(Name = "Name")]
        public string Name { get; set; }
    }
    
    public class Derived : Base {
        [Key]
        public int projectId {get; set; }
    }
    

    如果您不将 [Key] 放入 Derived,那么您将只有 ID 作为主键。当您将 [Key] 放入 Derived 时,您将只有 projectId 作为主键。您需要定义一个复合键,您可以通过从projectId 中删除[Key] 注释并使用onModelCreating 覆盖DbContext 来做到这一点

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Derived>().HasKey(a => new { a.ID, a.projectId })
                                        .Property(c => c.ID).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None);
        modelBuilder.Entity<Derived>().Property(c => c.projectId).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None);
    }
    
  • 您可以混合使用这些替代方案。您可以在 ID 字段上删除主键,然后您可以插入一个新实体,该实体将模拟 ID 和项目 ID 之间的 1-M 关系。

【讨论】:

  • 这解决了我的问题。非常好的答案,有多种不错的选项可供选择,以及重复代码的设计问题的解决方案。非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-11
  • 1970-01-01
  • 2012-11-07
  • 1970-01-01
相关资源
最近更新 更多