这是我的问题:每次我尝试向数据库中添加一行时,都会出现以下异常:
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/