在关于Entity Framework和MERGE的this SO answer中,如何编写代码的示例如下:
public void SaveOrUpdate(MyEntity entity)
{
if (entity.Id == 0)
{
context.MyEntities.AddObject(entity);
}
else
{
context.MyEntities.Attach(entity);
context.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
}
}
这假设您已经知道要嵌入的实体是否存在;在这种情况下,请检查entity.Id
。但是,如果您不知道该项目是否存在,该怎么办?例如,在我的情况下,我将来自供应商的记录导入我的数据库,并且可能已经或可能没有导入给定记录。我想更新记录,如果它存在,否则添加它。但两种情况下都已设置供应商的ID。
除非我只是询问数据库是否已经存在记录,否则我无法看到任何方法。
答案 0 :(得分:23)
我在这种情况下使用AddOrUpdate。但是,我相信它首先会查询数据库,以便决定发布插入或更新。
context.MyEntities.AddOrUpdate(e => e.Id, entity);
更新
我浏览了调试日志文件。首先它运行:
SELECT TOP (2) ... WHERE 1 = [Extent1].[Id]
然后它运行:
INSERT [dbo].[TestTable](...) VALUES (...)
SELECT [Id]
FROM [dbo].[TestTable]
WHERE @@ROWCOUNT > 0 AND [Id] = scope_identity()
OR:
UPDATE [dbo].[TestTable]
SET ...
WHERE ([Id] = @2)
更新2: 这是一个有趣的扩展方法,使用MERGE: https://gist.github.com/ondravondra/4001192
答案 1 :(得分:9)
AddOrUpdate是一个很好的解决方案,但它不是可扩展。需要一个数据库往返来检查实体是否已经存在以及插入或更新实体的一次往返。因此,如果您保存1000个实体,将执行2000数据库往返。
免责声明:我是该项目的所有者Entity Framework Extensions
此库允许您在实体框架内执行合并操作,同时显着提高性能。只需要1个数据库往返就可以保存1000个实体。
// Easy to use
context.BulkMerge(customers)
// Easy to customize
context.BulkMerge(customers, operation => {
operation.ColumnPrimaryKeyExpression =
customer => customer.Code;
});
答案 2 :(得分:9)
如果您需要没有存储过程的原子数据库UPSERT命令,并且您不担心要更新的上下文,则可能值得一提的是您还可以在{{中包装嵌入式MERGE
语句1}}来电:
ExecuteSqlCommand
这并不漂亮,因为它在EF的实体抽象之外工作,但它允许你利用public void SaveOrUpdate(MyEntity entity)
{
var sql = @"MERGE INTO MyEntity
USING
(
SELECT @id as Id
@myField AS MyField
) AS entity
ON MyEntity.Id = entity.Id
WHEN MATCHED THEN
UPDATE
SET Id = @id
MyField = @myField
WHEN NOT MATCHED THEN
INSERT (Id, MyField)
VALUES (@Id, @myField);"
object[] parameters = {
new SqlParameter("@id", entity.Id),
new SqlParameter("@myField", entity.myField)
};
context.Database.ExecuteSqlCommand(sql, parameters);
}
命令。
答案 3 :(得分:0)
您可以更改实体框架生成的INSERT或UPDATE sql的唯一方法是configure your model to use stored procedures。
然后,您可以修改Up迁移中生成的sql以创建插入和更新过程以使用MERGE sql而不是INSERT和UPDATE
CREATE PROCEDURE [dbo].[Blog_Insert]
@Name nvarchar(max),
@Url nvarchar(max)
AS
BEGIN
-- Your Merge Sql goes here
--And you need to use MERGE OUTPUT to get the primary key
--instead of SCOPE_IDENTITY()
--SELECT SCOPE_IDENTITY() AS BlogId
END