c# - EF 使用新引用更新现有实体并获取违反唯一键约束

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

我正在尝试更新数据库实体 (MamConfiguration_V1) 中的现有实体,称之为父级

我要

1) 给它添加一个引用(导航)成员 (MamConfigurationToBrowser_V1) 称它为 Child

2) 我不更改父实体中唯一属性的值。 (家长姓名)

我从数据库中获取了要更新的实体,

并使用相同的上下文 (mMamDbEntities)

我添加了引用成员。

我不更改它的 Name 属性。

但是我遇到了一个数据库错误,违反了唯一性限制

{"Violation of UNIQUE KEY constraint 'UQ_MamConfigurations_V1'. Cannot insert duplicate key in object 'dbo.MamConfiguration_V1'. The duplicate key value is (elad_14Apr_1315).\r\nThe statement has been terminated."}

我做了数据库嗅探并看到了生成的代码:

exec sp_executesql N'update [dbo].[MamConfiguration_V1]
set [Name] = @0, [Description] = @1, [StatusId] = @2, [Type] = @3, [UpdatedDate] = @4, [PercentageTraffic] = @5, [NumericTraffic] = @6
where ([ConfigurationId] = @7)
',N'@0 nvarchar(50),@1 nvarchar(200),@2 int,@3 int,@4 datetime2(7),@5 int,@6 int,@7 int',@0=N'elad_17Apr_1120_tmpToRemove_',@1=N'elad_22Apr_1120',@2=2,@3=0,@4='2013-04-23 11:17:25.4991650',@5=55,@6=-1,@7=32

//更多命令

exec sp_executesql N'insert [dbo].[MamConfiguration_V1]([Name], [Description], [StatusId], [Type], [CreatedDate], [UpdatedDate], [PercentageTraffic], [NumericTraffic])
values (@0, @1, @2, @3, @4, @5, @6, @7)
select [ConfigurationId]
from [dbo].[MamConfiguration_V1]
where @@ROWCOUNT > 0 and [ConfigurationId] = scope_identity()',N'@0 nvarchar(50),@1 nvarchar(200),@2 int,@3 int,@4 datetime2(7),@5 datetime2(7),@6 int,@7 int',@0=N'elad_17Apr_1120_tmpToRemove_',@1=N'elad_22Apr_1120',@2=2,@3=0,@4='0001-01-01 00:00:00',@5='0001-01-01 00:00:00',@6=55,@7=-1

我原以为 upsert 是 @@ROWCOUNT = 0

我做错了什么?

我的代码和数据库是:

        public void SaveCofiguration(MamConfiguration_V1Ui itemUi)
        {
            var itemEf = mMamConfiguration_V1UiToEfConvertor.ConvertToNewEf(itemUi);

            using (var maMDBEntities = new MaMDBEntities())
            {
                IDal<MamConfiguration_V1> mamConfigurationDal = mDalFactory.GetDal<MamConfiguration_V1>(maMDBEntities);

                mamConfigurationDal.Save(itemEf);
            }
        }

         public MamConfiguration_V1 GetById(object id)
        {           
                id.ThrowIfNull("id");

                int configurationId = Convert.ToInt32(id);

                var result =
                    mMaMDBEntities.MamConfiguration_V1.SingleOrDefault(item => item.ConfigurationId == configurationId);

                return result;

        }

       public MamConfiguration_V1 Save(MamConfiguration_V1 item)
        {

                item.ThrowIfNull("item");

                var itemFromDB = GetById(item.ConfigurationId);

                if (itemFromDB != null)
                {
                    UpdateEfItem(itemFromDB, item);

                   // if (mMaMDBEntities.ObjectStateManager.GetObjectStateEntry(itemFromDB).State == EntityState.Detached)
//                    {
  //                      mMaMDBEntities.MamConfiguration_V1.AddObject(itemFromDB);
    //                }

                    // Attached object tracks modifications automatically
                    mMaMDBEntities.SaveChanges();

                    return item;
                }





       private void UpdateEfItem(MamConfiguration_V1 itemFromDb, MamConfiguration_V1 itemFromUi)
            {
                itemFromDb.UpdatedDate = DateTime.Now;

                itemFromDb.Description = itemFromUi.Description;

                itemFromDb.StatusId = itemFromUi.StatusId;

                itemFromDb.Name = itemFromUi.Name;

                itemFromDb.NumericTraffic = itemFromUi.NumericTraffic;

                itemFromDb.PercentageTraffic = itemFromUi.PercentageTraffic;

                itemFromDb.Type = itemFromUi.NumericTraffic;

                foreach (var item in itemFromDb.MamConfigurationToBrowser_V1.ToList())
                {
                    if (itemFromUi.MamConfigurationToBrowser_V1.All(b => b.BrowserVersionId != item.BrowserVersionId))
                    {
                        mMaMDBEntities.MamConfigurationToBrowser_V1.DeleteObject(item);
                    }
                }

                for (int i = 0; i < itemFromUi.MamConfigurationToBrowser_V1.Count; i++)
                {
                    var element = itemFromUi.MamConfigurationToBrowser_V1.ElementAt(i);
                    var item = itemFromDb.MamConfigurationToBrowser_V1.SingleOrDefault(b => b.BrowserVersionId == element.BrowserVersionId);
                    if (item != null)
                    {
                        // copy properties from element to item
                    }
                    else
                    {
                        element.Browser = mMaMDBEntities.Browsers.Single(browserItem =>
                            browserItem.BrowserID == element.BrowserID);

                        //element.MamConfiguration_V1 = itemFromDb;

                        //have also tried: element.MamConfiguration_V1 = null;

                        //element.MamConfiguration_V1Reference = null;

                        itemFromDb.MamConfigurationToBrowser_V1.Add(element);
                    }
                }
            }

更新:

mMaMDBEntities.SaveChanges(); 抛出异常

这些是数据库表:

CREATE TABLE [dbo].[MamConfiguration_V1](
    [ConfigurationId] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](50) NOT NULL,
    [Description] [nvarchar](200) NOT NULL,
    [StatusId] [int] NOT NULL,
    [Type] [int] NOT NULL,
    [CreatedDate] [datetime2](7) NOT NULL,
    [UpdatedDate] [datetime2](7) NOT NULL,
    [PercentageTraffic] [int] NOT NULL,
    [NumericTraffic] [int] NOT NULL,
 CONSTRAINT [PK_MamConfigurations_V1] PRIMARY KEY CLUSTERED 
(
    [ConfigurationId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [SECONDARY],
 CONSTRAINT [UQ_MamConfigurations_V1] UNIQUE NONCLUSTERED 
(
    [Name] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [SECONDARY]
) ON [SECONDARY]

GO

ALTER TABLE [dbo].[MamConfiguration_V1]  WITH CHECK ADD  CONSTRAINT [FK_MamConfiguration_V1_ConfigurationType_V1] FOREIGN KEY([StatusId])
REFERENCES [dbo].[MamConfigurationStatuses] ([StatusId])
GO

ALTER TABLE [dbo].[MamConfiguration_V1] CHECK CONSTRAINT [FK_MamConfiguration_V1_ConfigurationType_V1]
GO

ALTER TABLE [dbo].[MamConfiguration_V1] ADD  CONSTRAINT [DF_MamConfigurations_V1_CreatedDate]  DEFAULT (getdate()) FOR [CreatedDate]
GO

ALTER TABLE [dbo].[MamConfiguration_V1] ADD  CONSTRAINT [DF_MamConfigurations_V1_UpdatedDate]  DEFAULT (getdate()) FOR [UpdatedDate]
GO




CREATE TABLE [dbo].[MamConfigurationToBrowser_V1](
    [MamConfigurationId] [int] NOT NULL,
    [BrowserVersionId] [uniqueidentifier] NOT NULL,
    [IsWhiteListed] [bit] NOT NULL,
    [BrowserID] [int] NOT NULL,
    [VersionNumberLowRange] [varchar](50) NOT NULL,
    [CreatedDate] [datetime] NOT NULL,
    [UpdatedDate] [datetime] NOT NULL,
    [VersionNumberUpperRange] [varchar](50) NULL,
 CONSTRAINT [PK_MamConfigurationToBrowser_V1_1] PRIMARY KEY CLUSTERED 
(
    [BrowserVersionId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [SECONDARY]
) ON [SECONDARY]

GO

SET ANSI_PADDING OFF
GO

ALTER TABLE [dbo].[MamConfigurationToBrowser_V1]  WITH CHECK ADD  CONSTRAINT [FK_MamConfigurationToBrowser_V1_Browsers] FOREIGN KEY([BrowserID])
REFERENCES [dbo].[Browsers] ([BrowserID])
GO

ALTER TABLE [dbo].[MamConfigurationToBrowser_V1] CHECK CONSTRAINT [FK_MamConfigurationToBrowser_V1_Browsers]
GO

ALTER TABLE [dbo].[MamConfigurationToBrowser_V1]  WITH CHECK ADD  CONSTRAINT [FK_MamConfigurationToBrowser_V1_BrowserVersion] FOREIGN KEY([MamConfigurationId])
REFERENCES [dbo].[MamConfiguration_V1] ([ConfigurationId])
GO

ALTER TABLE [dbo].[MamConfigurationToBrowser_V1] CHECK CONSTRAINT [FK_MamConfigurationToBrowser_V1_BrowserVersion]
GO

ALTER TABLE [dbo].[MamConfigurationToBrowser_V1] ADD  CONSTRAINT [DF_Browser_V1_CreatedDate]  DEFAULT (getdate()) FOR [CreatedDate]
GO

ALTER TABLE [dbo].[MamConfigurationToBrowser_V1] ADD  CONSTRAINT [DF_Browser_V1_UpdatedDate]  DEFAULT (getdate()) FOR [UpdatedDate]
GO

更新 2

我试过@AzharKhorasany 的解决方案,但出现了同样的错误:

for (int i = 0; i < itemFromUi.MamConfigurationToBrowser_V1.Count; i++)
            {
                var element = itemFromUi.MamConfigurationToBrowser_V1.ElementAt(i);
                var item = itemFromDb.MamConfigurationToBrowser_V1.SingleOrDefault(b => b.BrowserVersionId == element.BrowserVersionId);
                if (item != null)
                {
                    // copy properties from element to item
                }
                else
                {
                    element.Browser = mMaMDBEntities.Browsers.Single(browserItem =>
                        browserItem.BrowserID == element.BrowserID);

                    element.MamConfigurationId = itemFromDb.ConfigurationId;

                    //element.MamConfiguration_V1 = itemFromDb;

                    //have also tried: element.MamConfiguration_V1 = null;

                    //element.MamConfiguration_V1Reference = null;
                    //mMaMDBEntities.AddToMamConfigurationToBrowser_V1(itemFromUi.MamConfigurationToBrowser_V1.ElementAt(0)); // add as inserted

                    itemFromDb.MamConfigurationToBrowser_V1.Add(element);
                }
            }

最佳答案

您的代码非常冗长,其中很多与实际保存操作无关,但我想我明白您在做什么。首先,根据错误,您确实定义了新项目的 ID,它代表数据库中的某些内容,我想这就是您所期望的。

当您使用 Add() 时,您是在告诉 EF 您有新的东西,而它告诉您它已经有了。您反而/另外需要将实体状态从“已添加”更改为“未更改”。在 EF 中,您可以使用以下语法执行此操作:

DbContext.Entry(entity).State = EntityState.Unchanged;

还有其他方法可以做到这一点,所以请稍微研究一下。此外,EF 有一些辅助代码可以自动将值从一个实例复制到另一个实例。您需要搜索细节,但一般语法是:

DbContext.Entry(entityforUpdate).CurrentValues.SetValues(updatedDetachedEntity)

祝你好运!

关于c# - EF 使用新引用更新现有实体并获取违反唯一键约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16133182/

相关文章:

c# - 无法在对象中插入重复的键行

c# - 将属性注册为 DependencyProperty

sql - SQLite 中的物化 CTE

mysql - WITH ROLLUP 结合多个 GROUP BY 条件

mysql - 错误代码 : 1822. 添加外键约束失败。引用表 'ekdromes_ibfk_1' 中缺少约束 'pwlhseis' 的索引

c# - 模型中的 MVC Controller 列表未绑定(bind)

c# - 命名用户控件。习俗?

c# - LINQ to SQL : Advanced queries against lists, 数组和对象列表

c# - 如何在 MVC 应用程序和控制台应用程序之间共享信息

javascript - 获取输入范围以在页面加载时显示值,并提交 slider 值作为答案?