【问题标题】:Entity Framework setting foreign key, primary key violation实体框架设置外键,违反主键
【发布时间】:2022-11-19 01:23:39
【问题描述】:

尝试创建类型为 TestForm2 的新数据库条目时,我将相关对象单元类型的 ID 作为外键包含在内,除非我在添加新模型后执行 context.SaveChanges() 时出现以下 SQL 异常:

SqlException:违反 PRIMARY KEY 约束“PK_dbo.UnitTypes”。无法在对象“dbo.UnitTypes”中插入重复键。重复键值为 (2d911331-6083-4bba-a3ad-e50341a7b128)。该语句已终止。

这对我来说意味着它认为我试图与新模型关联的外部条目是一个新对象,它试图插入到 UnitTypes 表中但失败了,因为它看到一个具有相同主键的现有条目.

对于上下文(双关语不是故意的),这是我的数据上下文、数据库模型和错误的“创建”函数。

public class DataContext : IdentityDbContext<ApplicationUser>
    {
        public DataContext() : base("DefaultConnection")
        {
        }
        public static DataContext Create()
        {
            return new DataContext();
        }
        public DbSet<SafetyIncident> SafetyIncidents { get; set; }
        public DbSet<ProductionLine> ProductionLines { get; set; }
        public DbSet<ProductionOrder> ProductionOrders { get; set; }
        public DbSet<SerialOrder> SerialOrder { get; set; }
        public DbSet<QualityError> QualityErrors { get; set; }
        public DbSet<PSA> PSAs { get; set; }
        public DbSet<TestStation> TestStations { get; set; }
        public DbSet<ProductionGoal> ProductionGoals { get; set; }
        public DbSet<DailyWorkStationCheck> DailyWorkStationChecks { get; set; }
        public DbSet<TestForm> TestForms { get; set; }
        public DbSet<User> AppUsers { get; set; }
        public DbSet<Options> Options { get; set; }
        public DbSet<DriveList> DriveSerials { get; set; }
        public DbSet<MRPController> MRPControllers { get; set; }
        public DbSet<TestOption> TestOptions { get; set; }
        public DbSet<UnitType> UnitTypes { get; set; }
        public DbSet<UnitTypeMap> UnitTypeMaps { get; set; }
        public DbSet<TestForm2> TestForm2s { get; set; }
        public DbSet<TestFormSection> TestFormSections { get; set; }
        public DbSet<TestFormSectionStep> TestFormSectionSteps { get; set; }
    }
public class TestForm2 : BaseEntity
    {
        public string SerialNumber { get; set; }
        public string MaterialNumber { get; set; }
        public string UnitTypeId { get; set; }
        public UnitType UnitType { get; set; }
        public bool UsesStandardOptions { get; set; }
        public bool OptionsVerified { get; set; } // This will only be used when UsesStandardOptions is true, otherwise its value doesn't matter
        public ICollection<TestOption> AllOptions { get; set; } // List of all options (at time of form creation)
        public ICollection<TestOption> Options { get; set; } // The options on a unit
        public ICollection<TestFormSection> Sections { get; set; }
    }
public FormViewModel Create(FormViewModel vm)
        {
            using (var context = new DataContext())
            {
                List<string> optionListStrings = GetOptionListForModelNumber(vm.MaterialNumber); // returns list of option codes
                List<TestOption> matchingOptions = context.TestOptions
                    .Where(optionInDb =>
                        optionListStrings.Any(trimOption => trimOption == optionInDb.OptionCode)).ToList();

                var unitType = context.UnitTypes.FirstOrDefault(x => x.Name == vm.UnitType);
                string unitTypeId = unitType.Id;

                TestForm2 newForm = new TestForm2
                {
                    // ID & CreatedAt instantiated by Base Entity constructor
                    SerialNumber = vm.SerialNumber,
                    MaterialNumber = vm.MaterialNumber,
                    UnitTypeId = unitType.Id,
                    UsesStandardOptions = vm.UsesStandardOptions,
                    OptionsVerified = vm.OptionsVerified,
                    //AllOptions = context.TestOptions.ToList(),
                    //Options = matchingOptions,
                    Sections = vm.Sections,
                };

                context.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
                context.TestForm2s.Add(newForm);
                context.SaveChanges(); // THIS IS WHERE THE SQL EXCEPTION IS HAPPENING
 
                return vm;
            }

            return null;
        }

最后,我不确定它是否相关,但只有在 context.TestForm2s.add(newForm) 解析后,相关 UnitType 的完整副本才可作为 newForm 的一部分查看。这对我来说很奇怪,因为我认为它不应该像那样自动关联数据对象。

我没能尝试太多,因为对我来说一切看起来都配置正确。如果不是这种情况,或者我是否应该包含任何其他信息,请告诉我。

【问题讨论】:

  • 你能说明你在哪里定义了外键关系吗?
  • @Andrew 外键是 UnitTypeId。在“Create”方法期间,从具有来自 FormViewModel (vm.UnitType) 的相同“Name”字段的适当的 UnitType 对象查询它。这是一个 link to an image 显示关系已正确定义。

标签: c# sql-server asp.net-mvc entity-framework


【解决方案1】:

发现了问题。 vm.Sections 是不是使用视图模型包含部分数据,因此 vm.Sections 包含 UnitType 数据库模型。由于这是在控制器中实例化的(在 TestForm2 Create 方法中打开数据上下文之前)EF 假定这些数据是新的并且需要添加到 UnitType 表中。

希望此线程可以帮助遇到类似问题的其他人。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-11
    • 1970-01-01
    • 2011-07-20
    • 2010-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多