我在使用Entity Framework 6的MVC Web应用程序后面的数据库中有以下简化表定义和过滤的唯一索引。
//package.json
{
"name": "http-server",
"main": "server.js",
"dependencies": {
"express": "^4.13.4"
}
}
//server.js
var express = require('express');
var app = express();
var path = require('path');
app.get('/', function (res, req) {
res.sendFile(path.join(__dirname + '/index.html'));
});
app.listen(1337);
console.log('Visit me at http://localhost:1337');
唯一索引会阻止多个CREATE TABLE [dbo].[ItemImage](
[ItemId] [int] NOT NULL,
[stream_id] [uniqueidentifier] ROWGUIDCOL NOT NULL,
[Primary] [bit] NOT NULL,
[Caption] [nvarchar](1000) NULL,
CONSTRAINT [PK_ItemImage_ItemId_stream_id] PRIMARY KEY CLUSTERED ([ItemId] ASC, [stream_id] ASC)
CONSTRAINT [FK_ItemImage_ItemId_Item] FOREIGN KEY([ItemId]) REFERENCES [dbo].[Item] ([ItemId])
);
GO
CREATE UNIQUE NONCLUSTERED INDEX [UXF_ItemImage_ItemId_Primary]
ON [dbo].[ItemImage] ([ItemId] ASC)
WHERE ([Primary] = 1);
GO
设置[ItemId]
位标志。
在MVC控制器中,我有一组[Primary]
视图模型,我正在更新EF模型,如下所示:
ItemImage
当调用...
foreach (var img in itemViewModel.ItemImages)
{
var itemImage = item.ItemImages.First(i => i.stream_id == img.stream_id);
itemImage.Primary = img.Primary;
itemImage.Caption = img.Caption;
}
...
await db.SaveChangesAsync();
时,我得到以下异常:
无法在对象'dbo.ItemImage'中插入具有唯一索引'UXF_ItemImage_ItemId_Primary'的重复键行。重复键值是(146)。 声明已经终止。
我在更新之前有逻辑阻止db.SaveChangesAsync()
有多个“主要”Item
。
我认为这种情况正在发生,因为当Entity Framework尝试更新数据库中的ItemImages集合时,它会在取消设置当前设置的行之前将另一行的ItemImages
标志设置为[Primary]
。
有没有办法强制实体框架中的更新顺序?或者我有可以实施的解决方法吗?
答案 0 :(得分:0)
不确定这是否是最有效的方法,但它现在正在使用以下方法。
foreach (var img in itemViewModel.ItemImages.Where(i => ! i.Primary))
{
var itemImage = item.ItemImages.First(i => i.stream_id == img.stream_id);
itemImage.Primary = img.Primary;
itemImage.Caption = img.Caption;
}
await db.SaveChangesAsync();
var primaryImage = itemViewModel.ItemImages.First(i => i.Primary);
var itemImagePrimary = item.ItemImages.First(i => i.stream_id == primaryImage.stream_id);
itemImagePrimary.Primary = primaryImage.Primary;
itemImagePrimary.Caption = primaryImage.Caption;
await db.SaveChangesAsync();
基本上我只是批量更新所有“非主要”ItemImages
,提交更改,然后更新新的“主要”。
答案 1 :(得分:0)
更有效的方法是通过存储过程将更新推送到数据库层。
CREATE PROCEDURE [dbo].[uspItemImage_SetPrimary]
@itemId INT
, @stream_id UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON;
IF NOT EXISTS ( SELECT NULL FROM [dbo].[ItemImage] WHERE [ItemId] = @itemId AND [stream_id] = @stream_id )
BEGIN
DECLARE @stream_id_vc NVARCHAR(36) = CONVERT(NVARCHAR(36), NEWID());
RAISERROR( N'No ItemImage exists with ItemId = %d and stream_id = ''%s''',
11,
1,
@itemId,
@stream_id_vc);
END;
BEGIN TRANSACTION;
UPDATE
[dbo].[ItemImage]
SET
[Primary] = 0
WHERE
[ItemId] = @itemId;
UPDATE
[dbo].[ItemImage]
SET
[Primary] = 1
WHERE
[ItemId] = @itemId AND
[stream_id] = @stream_id;
COMMIT TRANSACTION;
RETURN 0;
END;
将存储过程作为SetPrimaryItemImage
导入实体框架模型后,我可以简单地执行以下操作:
...
foreach (var img in itemViewModel.Images)
{
var itemImage = item.ItemImages.First(i => i.stream_id == img.stream_id);
itemImage.Caption = img.Caption;
}
await db.SaveChangesAsync();
db.SetPrimaryItemImage(item.ItemId, itemViewModel.Images.First(i => i.Primary).stream_id);
...