实体框架 - 独特索引上的UPSERT

Hel*_*aby 20 c# sql entity-framework upsert

我搜索了一下我的问题,但找不到任何真正有用的东西.

所以我的问题/困境保持这样:我知道mysql数据库有一个唯一的索引系统,可以使用这种格式在同一查询中插入/更新: insert into t(a,b,c) values(1,1,1) on duplicate keys update b=values(b),c=values(c); 以及用于替换该索引的现有记录的替换格式.

说实话,我在MSSQL中看到的唯一类似的东西是,merge但我真的不喜欢它,并且验证插入或更新的查询根本不是唯一的索引...

那么如何将mysql独特的UPSERT模拟到Entity Framework中呢?这是我的主要问题......

我的意思是没有从实体集中获取记录并检查它是否为null或者是否为可能的插入或更新;

我能得到它吗?或不?任何提示都可能有用

我看到了这个,但没有出现在版本6中......

实体的例子:

    [Table("boats")]
    public class Boat
    {
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int id { get; set; }
        [MaxLength(15)]
        [Index("IX_ProviderBoat",1,IsUnique=true)]
        public string provider_code { get; set; }
        public string name { get; set; }
        [Index("IX_ProviderBoat", 3, IsUnique = true)]
        [MaxLength(50)]
        public string model { get; set; }
        [Index("IX_ProviderBoat", 2, IsUnique = true)]
        [MaxLength(15)]
        [Key]
        public string boat_code { get; set; }
        public string type { get; set; }
        public int built { get; set; }
        public int length { get; set; }            
    }
Run Code Online (Sandbox Code Playgroud)

所以我想使用EF基于我的IX_ProviderBoat唯一索引更新/插入

在此输入图像描述

wah*_*wah 19

AddOrUpdate方法是IDBSetEF6 的成员并在EF6中可用.

AddOrUpdate方法不是原子操作,来自多个线程的调用不保证第二个线程Update而不是Add再次 - 因此您可以获得存储的重复记录.

这个例子经过测试并符合您的期望:

        Boat boat = new Boat // nullable fields omitted for brevity 
        {
            boat_code = "HelloWorld",
            id = 1,
            name = "Fast Boat",
            built = 1,
            length = 100
        };

        using (BoatContext context = new BoatContext()) // or whatever your context is
        {
            context.Set<Boat>().AddOrUpdate(boat); // <-- IDBSet!!!
            context.SaveChanges();
        }
Run Code Online (Sandbox Code Playgroud)

如果我们改变boat_codeAddOrUpdate()方法,将添加一个新的记录.如果boat_code是'HelloWorld`,它将更新现有记录.我相信这就是你要找的......

希望这可以帮助!

  • 只是你知道......这个upsert不是线程安全的...正如我前几天在生产中发现的那样...> _ < (11认同)
  • `.AddOrUpdate`用于`Migrations`,因此命名空间.它适用于DbInitializer.初始化程序是单线程的.问题是"MERGE"做了一些完全不同的事情.我的观点是OP要小心它! (9认同)
  • 两个线程,两个上下文,相同的命令,同一时间.重复插入......很有趣!我曾希望EF会原子地使用`MERGE`.但它使用select/insert/update. (8认同)
  • 通常,当一个人要求Upsert时,人们想要一个原子(并且可能是幂等)方法.我的问题是两个线程(具有不同的DbContexts)同时使用相同的列表调用`.AddOrUpdate`.如果没有适当的索引,我最终会有重复的条目(如果我有适当的索引,我会有例外).`SQL Server`使用`MERGE`命令支持原子upsert.但EF并没有使用它. (6认同)
  • 我的天啊.这与Disposal无关.我没有重复使用上下文.你有没有读过EF的源代码......我告诉你`.AddOrUpdate`不是线程安全的.https://entityframework.codeplex.com/SourceControl/latest#src/EntityFramework/Migrations/DbSetMigrationsExtensions.cs (5认同)