【问题标题】:Avoid duplicate entries in Entity Framework, using MSSQL and .Net Core使用 MSSQL 和 .Net Core 避免实体框架中的重复条目
【发布时间】:2020-02-28 12:06:02
【问题描述】:

我有 2 个相关的表,它们是组件和零件。

我的组装课:

public class Assembly{
  public int Id { get; set; }
  public string No{ get; set; }
  public string Name { get; set; }

  public int? ParentId { get; set; }
  public Assembly Parent { get; set; }

  public List<Assembly> Children { get; set}
  public List<Part> Parts { get; set; }
}

我的零件类:

public class Part{
   public int Id { get; set; }
   public string No { get; set; }
   public string Name { get; set; }
   public string Image { get; set; }

   public int AssemblyId { get; set;}
   public Assembly Assembly { get; set; }
}

我要做的是,首先我在控制器中创建程序集。 然后当我创建一个Assembly时,一个文件上传页面正在打开,然后我上传一个Excell文件并将excell数据映射到我的Part Object作为对我的Assembly对象的引用。(每个部件AssemblyId都是AssemblyId来自路由)

但这有一个很大的问题,因为大多数组件在其零件列表中都有相同的零件或零件。

例如,假设有一个零件,零件编号:555,零件名称:车轴。

假设我要在我的项目中创建 5 个程序集。每个程序集都将从不同的 Excel 文件中导入数据。

每个 Excell 都包含相同的零件,其零件编号:555 和零件名称:Axle,但显然具有不同的 AssemblyId(FK)。

但仍然在我的数据库中,有很多零件与其重复项具有相同的信息,但差别不大的是它们的 AssemblyId 列不同并且引用了 AssemblyId 中的另一个程序集。

我想要实现的是避免这种情况......

我不想重复我的数据。实际上我认为一个解决方案,但我不确定它是否是一个好的解决方案..我可能会做一个“if”语句并检查,同时从 Excell 上传数据,如果数据库中存在具有这些信息的部分,我可能不会上传那个特定的行到表中,并使用已经存在的部分。但我认为这会减慢我的项目。

希望我已经问清楚了..

【问题讨论】:

  • 许多部件与其重复项具有相同的信息,但 (...) 它们的 AssemblyId 列不同 这里最大的缺陷是您应该将其实现为多个一对多关系。
  • 我想给他们一个特殊的 AssemblyId 标识符,但现在我可以看到这完全是错误的方式......实际上我必须在 NN 关系中尝试这个......谢谢。跨度>

标签: sql .net asp.net-mvc database entity-framework


【解决方案1】:

这是一个关系设计问题,您的 Parts 表不应引用 Assembly 表。 装配表应仅引用零件 ID。

请考虑:

  • 若要为装配定义提供一个表,此表不应包含零件,只有装配。
  • 有一个用于装配零件关系的表。

public class Assembly_Part{ public int AssemblyId { get;设置;} 公共 int PartId { 获取;放; } }

  • 拥有与部件无关的部件表(从部件表中删除 AssemblyId)

如果您不希望某些零件成为特定装配的一部分,那么您应该为零件 ID-装配创建一个额外的关系。

当您将数据发送到数据库时,您应该发送与组件和零件 ID 相关的,而不是零件定义。

那么您的零件定义过程应该负责零件的创建,而不是装配的创建过程。

将零件添加到装配体时,如果两个过程一起执行,您可能会区分新零件和旧零件。

这是我的最佳方案:

  • 您想要创建一个装配体,您的流程将定义一个新的 AssemblyId 并允许您选择要包含在装配体中的零件。在 DB 中,您只会将记录添加到组装表。

  • 如果您需要新零件,则应在不同的流程中创建该零件,此流程将处理现有零件的零件创建和验证。在 DB 中,您只会将记录添加到 Parts Table。

  • 为装配加载零件时,您将创建一个列表,其中包含与当前搜索相关的所有零件,没有重复。

请参考:Database Design Best Practices

【讨论】:

    【解决方案2】:

    您可以覆盖您正在查看的任何类(在本例中为Part)的 equals 方法,并比较您关心的字段,以查看一个 Part 是否与您的应用程序上下文中的另一个相同。下面是一个简单的例子:

      public class Part 
      {
        public string Name { get; set; }
    
        public DateTime? InactiveDate { get; set; }
    
        public int AssemblyId {get; set;}
    
        public override bool Equals(object obj)
        {
          Part yVal = (Part) obj;
    
          if (yVal == null)
          {
            return false;
          }
    
          // compare each of the values we care about. i.e: NOT comparing AssemblyId
          return this.Name == yVal.Name
            && this.InactiveDate == yVal.InactiveDate;
        }
    

    当您要将新零件保存到数据库时,您将使用它,查看是否有任何现有零件.Equals 任何现有Part

    var existingPart = db.Parts.SingleOrDefault(x => myPartToSave.Equals(x))
    
    if(existingPart != null)
    {
        myAssemblyToSave.Parts.Remove(myPartToSave);
        myAssemblyToSave.Parts.Add(existingPart);
    }
    
    //then save your part as you normally would
    

    如果有,则使用现有的Part 保存您的Assembly,如果没有,请照常保存AssemblyPart

    注意:在实现此之前,最好编写一个 sql 脚本(或控制台应用程序,或任何您最熟悉的应用程序)以消除当前存在的任何重复项

    另一个注意事项:当您覆盖Equals 时,最好也覆盖GetHashCode 方法。我不会在这里详细说明为什么,因为它超出了这个问题的范围 - 你应该能够轻松找到这方面的信息。有一个很好的帖子就在here 上关于它

    【讨论】:

    • 我会尽快尝试,谢谢您的回答。
    • 检查相等是一个好主意,但仍然不能真正解决我的问题......这里的主要斗争是程序集是自引用数据结构(父子关系)和每个程序集有自己的零件清单...
    • 我了解组件和零件具有父子关系。仍然没有理由(至少在您的问题中)为什么这不起作用。此外,除非您的帖子中有拼写错误,否则Assembly 不是自引用(这将涉及其中包含 Assembly 类型的属性的 Assembly 类)请参阅 flylib.com/books/en/2.255.1/self_referential_classes.html
    • 这是一个自引用结构,我在创建问题时忘记写它,这是一个错误...让我编辑。不过谢谢。
    • 这根本不会影响建议的解决方案 - 这仍然有效。如果您发布您用来尝试的实际代码,那么我们可以帮助您解决问题。如果没有,我在这里无能为力。不管你在做什么,当一个新的部分要被保存时,你需要检查它是否已经存在于数据库中,如果它存在就使用现有的,以防止重复。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多