c# - Entity Framework 6 DbUpdateConcurrencyException 将新行添加到数据库时

标签 c# mysql entity-framework-6 ef-fluent-api

这是我的问题:每次我尝试向数据库中添加一行时,都会出现以下异常:
DbUpdateConcurrencyException

除了我,没有其他人使用这个开发数据库。请帮忙。我在我的智慧在这里结束。

这是代码:

using (var context = new MyDbContext(connectionString))
{
    context.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);

    var newProduct = new ProductsEntity { ProductTypeId = 1 };
    context.Products.Add(newProduct);

    // The line below always throws the exception
    context.SaveChanges();
}

上下文, MyDbContext 定义如下:
public class MyDbContext : DbContext
{
    public MyDbContext(string connectionString) : base(connectionString)
    {
        System.Data.Entity.Database.SetInitializer<MyDbContext>(null);
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new ProductsMap());
    }

    public virtual DbSet<ProductsEntity> Products { get; set; }
}

产品 map 产品实体 定义如下:
public class ProductsMap : EntityTypeConfiguration<ProductsEntity>
{
    HasKey(t => t.ProductId);

    ToTable("Products");

    Property(t => t.ProductId)
        .HasColumnName("ProductId")
        .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

    Property(t => t.ProductTypeId)
        .HasColumnName("ProductTypeId");

    // Stored Procedure Mapping
    MapToStoredProcedures(s =>
        s.Insert((i => i.HasName("InsertProduct")
            .Parameter(p => p.ProductTypeId, "ProductTypeId")
            .Result(r => r.ProductId, "ProductId")
            )));
}

public class ProductsEntity
{
    public int ProductId { get; set; }
    public int ProductTypeId { get; set; }
}

存储过程,插入产品 在这儿:
CREATE PROCEDURE [dbo].[InsertProduct]    

@ProductTypeId int,  
@Identity int = NULL OUTPUT  

AS  
BEGIN    

INSERT INTO [dbo].[Products]  
    ( [ProductTypeId] ) 
    VALUES 
    ( @ProductTypeId  )    

END    

SET @Identity = SCOPE_IDENTITY()  

RETURN   

并且,表产品 定义如下:
CREATE TABLE dbo.Products
(
    ProductId int IDENTITY(1,1) NOT NULL,
    ProductTypeId int NOT NULL,
PRIMARY KEY CLUSTERED
(
    ProductId ASC
) WITH (
    PAD_INDEX  = OFF, 
    STATISTICS_NORECOMPUTE  = OFF, 
    IGNORE_DUP_KEY = OFF, 
    ALLOW_ROW_LOCKS  = ON, 
    ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]) 
ON [PRIMARY]

GO

ALTER TABLE dbo.Products WITH CHECK ADD FOREIGN KEY(ProductTypeId)
REFERENCES dbo.ProductTypes (ProductTypeId)

GO

如果有帮助的话,似乎正在发生的事情是 的身份种子产品 实际上,每次代码到达 时,表格都会增加。 SaveChanges() 下面的行。我可以说,因为当我测试运行时 插入产品 在 SQL Server Studio 中,产品编号 每次尝试运行此代码时,列都会跳过一个整数。

我最好的猜测是 Entity Framework 执行 插入产品 过程,但不知何故,事务被阻止并回滚。不过,老实说,我不知道。

这是控制台的调试输出内容:
Opened connection at 10/25/2016 5:53:43 PM -07:00

Started transaction at 10/25/2016 5:53:43 PM -07:00

[dbo].[InsertProduct]


-- ProductTypeId: '1' (Type = Int32, IsNullable = false)

-- Executing at 10/25/2016 5:53:44 PM -07:00

Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.RemoteDependency","time":"2016-10-26T00:53:44.0238952Z","tags":{"ai.operation.parentId":"CTWlUsYMEbU=","ai.device.roleInstance":"MyComputerName.Domain","ai.operation.name":"POST deal","ai.operation.id":"CTWlUsYMEbU=","ai.internal.sdkVersion":"rddf: 2.1.0.363"},"data":{"baseType":"RemoteDependencyData","baseData":{"ver":2,"name":"SERVERNAME| DevDatabase | [dbo].[InsertProduct]","id":"JDD838YyJkc=","value":16.0379,"dependencyKind":0,"success":true,"properties":{"DeveloperMode":"true"}}}}
-- Completed in 28 ms with result: SqlDataReader



Closed connection at 10/25/2016 5:53:44 PM -07:00

Exception thrown: 'System.Data.Entity.Infrastructure.DbUpdateConcurrencyException' in EntityFramework.dll

这是来自内部异常的文本:

"Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded."



而且,确实,没有插入任何行。再一次,没有其他人使用这个开发数据库;我是唯一拥有 dbo 权利的人。

编辑:找到解决方案

好的,非常感谢下面的@Juan 为我指明了正确的方向。问题确实是 EF 需要某种方式来了解主键发生了什么,但这非常微妙。

我做的第一件事是尝试像这样更改上面的存储过程:
CREATE PROCEDURE [dbo].[InsertProduct]    

@ProductTypeId int,  
@Identity int = NULL OUTPUT  

AS  
BEGIN    

INSERT INTO [dbo].[Products]  
    ( [ProductTypeId] ) 
    VALUES 
    ( @ProductTypeId  )    

END    

SET @Identity = SCOPE_IDENTITY()  
SELECT SCOPE_IDENTITY() // <-- Added this line

RETURN   

然后,发生的事情是抛出的异常更改为。数据库更新异常 (来自 DbUpdateConcurrencyException )。此外,内部异常文本现在如下所示:

A function mapping specifies a result column 'ProductId' that the result set does not contain.



嗯,这告诉我我正在取得进步。所以接下来我尝试的是更改 中的 Fluent API。产品 map 如下:
public class ProductsMap : EntityTypeConfiguration<ProductsEntity>
{
    HasKey(t => t.ProductId);

    ToTable("Products");

    Property(t => t.ProductId)
        .HasColumnName("ProductId")
        .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

    Property(t => t.ProductTypeId)
        .HasColumnName("ProductTypeId");

    // Stored Procedure Mapping
    // ------------------------
    // Changed the "ProductId" below to "Identity", since that is
    // the name of the output variable in the stored procedure
    MapToStoredProcedures(s =>
        s.Insert((i => i.HasName("InsertProduct")
            .Parameter(p => p.ProductTypeId, "ProductTypeId")
            .Result(r => r.ProductId, "Identity")
            )));
}

上面的这个更改抛出了相同的 数据库更新异常 ,但内部异常文本更改为:

A function mapping specifies a result column 'Identity' that the result set does not contain.



在这一点上,我注意到 Fluent API 中 .Result() 方法的工具提示如下(重点由我添加):

Configures a column of the result for this stored procedure to map to a property. This is used for database generated columns.



所以,这让我想到 Fluent API 中的 .Result() 方法可能根本不适用于 SQL 存储过程输出。我试图查找有关 EF6 的文档以了解该方法应该如何工作,但我找不到任何有用的东西。而且,我找不到任何使用 SQL 存储过程输出的示例,这很能说明问题。

所以相反,这让我注意到了我唯一的数据库生成列,这是一个:
    Property(t => t.ProductId)
        .HasColumnName("ProductId")
        .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

考虑到这一点,我将上面的存储过程更改如下:
CREATE PROCEDURE [dbo].[InsertProduct]    

@ProductTypeId int,  
@Identity int = NULL OUTPUT  

AS  
BEGIN    

INSERT INTO [dbo].[Products]  
    ( [ProductTypeId] ) 
    VALUES 
    ( @ProductTypeId  )    

END    

SET @Identity = SCOPE_IDENTITY()  
// Altered the line below a little bit
SELECT ProductId FROM Products WHERE ProductId = SCOPE_IDENTITY()

RETURN   

再一次,我得到了这个结果 数据库更新异常 , :

A function mapping specifies a result column 'Identity' that the result set does not contain.



所以,然后我想,我应该把 Fluent API 中的 .Result() 方法改回我以前的方法,也许一切都会好起来的:
    // Stored Procedure Mapping
    // ------------------------
    // Changed the "Identity" back to "ProductId"
    MapToStoredProcedures(s =>
        s.Insert((i => i.HasName("InsertProduct")
            .Parameter(p => p.ProductTypeId, "ProductTypeId")
            .Result(r => r.ProductId, "ProductId")
            )));

你猜怎么着?那行得通!

为了更好地衡量,我还尝试完全删除 .Result() 规范,如下所示:
    // Stored Procedure Mapping
    // ------------------------
    // No more .Result() specification
    MapToStoredProcedures(s =>
        s.Insert((i => i.HasName("InsertProduct")
            .Parameter(p => p.ProductTypeId, "ProductTypeId")
            )));

而且,有趣的是,这也很好用!

因此,最终,我的结论是,将列指定为 Fluent API 中生成的数据库可能与 下的 .Result() 方法的规范是多余的。 MapToStoredProcedures() .我在 EF6 文档中找不到任何东西来更好地解释这一点,但至少现在我可以解决这个问题。

再次感谢@Juan 的大力帮助,为我指明了正确的方向! :)

最佳答案

我想我可能知道问题出在哪里。

EF 未检测到插入。我认为这是因为您有一个名为 @Identity 的 OUTPUT 参数,但我没有看到它被映射回任何地方:

// Stored Procedure Mapping
MapToStoredProcedures(s =>
    s.Insert((i => i.HasName("InsertProduct")
        .Parameter(p => p.ProductTypeId, "ProductTypeId")
        .Result(r => r.ProductId, "ProductId")
        )));

要么将 @Identity 参数映射到 ProductId 字段,要么让 SP 返回标识以让 EF 知道插入成功:
SELECT SCOPE_IDENTITY();

关于c# - Entity Framework 6 DbUpdateConcurrencyException 将新行添加到数据库时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40252094/

相关文章:

c# - Web 应用程序和 Web 表单之间的混淆

c# - 任何将单独的数据访问层(使用 EF)突出显示到业务逻辑层的示例 C# 项目

c# - C# 中的 Sql Identity 仅插入值 0

以制表符终止的 MySQL 字段

java - java中内连接的解析结果【性能相关】

php - 接收订单详情和付款确认(电子商务网站)

c# - 奇怪的 Linq to Entities 行为与 AsExpandable()

c# - 在 WebBrowser 控件中将字符串数组从 JS 传递到 C#

c# - LINQ to SQL - 排序依据、分组依据以及每个组的排序,并带有skip和take

c# - Firebird embedded 和 Entity Framework 6 出现 "Unknown data type"错误