[英]Upsert in Microsoft.EntityFrameworkCore.SqlServer 5.0.8 C# with a composite key
I have a composite key ( sku
( nvarchar
/string value) and quantity
( int
value)) and I want to do an upsert in Microsoft.EntityFrameworkCore.SqlServer 5.0.8 using C#.我有一个复合键( sku
( nvarchar
/string 值)和quantity
( int
值)),我想在 Microsoft.EntityFrameworkCore.SqlServer 5.0.8 中使用 C# 做一个 upsert。
The AddOrUpdate
call is missing from the context - not that we're supposed to be using that anyway, since it's primarily meant for migrations.上下文中缺少AddOrUpdate
调用 - 并不是说我们无论如何都应该使用它,因为它主要用于迁移。
How do I accomplish this?我该如何实现?
Having a composite key means (as a compare to a single surrogate-key-primary-key)......it is still a "match and find or not find" proposition.拥有一个复合键意味着(作为与单个代理键-主键的比较)......它仍然是一个“匹配并找到或不找到”的命题。
First, the setup.首先,设置。
https://docs.microsoft.com/en-us/ef/core/modeling/keys?tabs=data-annotations#configuring-a-primary-key https://docs.microsoft.com/en-us/ef/core/modeling/keys?tabs=data-annotations#configuring-a-primary-key
You can also configure multiple properties to be the key of an entity您还可以将多个属性配置为实体的键
- this is known as a composite key.这称为复合键。 Composite keys can only be configured using the Fluent API;复合键只能使用 Fluent API 进行配置; conventions will never set up a composite key, and you can not use Data Annotations to configure one.约定永远不会设置复合键,并且您不能使用数据注释来配置一个。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Car>()
.HasKey(c => new { c.State, c.LicensePlate });
}
Then you will Add items to your dbContext.然后,您将向 dbContext 添加项目。 (like adding object(s) to a collection) (例如将对象添加到集合中)
for each CarEntity currentCar : myCarCollection)
{
/* this code may not work for the future copy-pasters out there..i'm building up a little, see "WHERE IN" later in this answer */
this.myEntityDbContext.MyCars.Add(currentCar);
}
Then you will call然后你会打电话
await this.myEntityDbContext.SaveChangesAsync(token);
(or the sync version .SaveChanges) (或同步版本 .SaveChanges)
EF ~~may be able (but probably not) to find existing-matches (and update existing) or insert new ones. EF ~~也许能够(但可能不能)找到现有匹配(并更新现有)或插入新匹配。 And it depends on the state of your myDbContext at the moment of impact.这取决于您的 myDbContext 在影响时刻的状态。 (Again, i'm trying to build this up a little bit with talking about it, instead of just giving a copy/paste answer...you gotta try to understand how EF is working a little...to get better at debugging it) (同样,我试图通过谈论它来建立这一点,而不是仅仅给出复制/粘贴答案......你必须尝试了解 EF 是如何工作的......以便更好地进行调试它)
with the M$ example.以 M$ 为例。
if the database already has a如果数据库已经有
c.State = "VA", c.LicensePlate = "2222-2222" c.State = "VA", c.LicensePlate = "2222-2222"
but does not have但没有
c.State = "WV", c.LicensePlate = "3333-3333" c.State = "WV", c.LicensePlate = "3333-3333"
Now, and you add both of these to your myDbContext (the "currentCar" code above) and then call "SaveChangesAsync"....that MIGHT work.现在,您将这两个添加到 myDbContext(上面的“currentCar”代码),然后调用“SaveChangesAsync”......这可能会起作用。 But it will probably fail.但它可能会失败。 That's ok.没关系。
Here is one "trick".这是一个“技巧”。 (it may not be the only one) (它可能不是唯一的)
You need to get the existing items (where VA/2222-2222 already exists) INTO the myDbContext.您需要将现有项目(其中 VA/2222-2222 已经存在)放入 myDbContext。
So before you do the MyCars.add....所以在你做 MyCars.add 之前......
call the EF equivalent of (rdbms WHERE IN ) ( see Entity Framework Core - IN clause equivalent )调用 (rdbms WHERE IN ) 的 EF 等效项(请参阅Entity Framework Core-IN 子句等效项)
and the values you try check against the EF version of "WHERE IN".....will be both combinations of the "Car".并且您尝试对照“WHERE IN”的 EF 版本检查的值......将是“Car”的两个组合。
I just read one of the comments.我刚刚阅读了其中一条评论。 Yes, that is very helpful.是的,这很有帮助。 For clarity, this link: Update Row if it Exists Else Insert Logic with Entity Framework为清楚起见,此链接: 更新行,如果它存在,则使用实体框架插入逻辑
That link is saying "how do i check for exist/not-exists IN THE DBCONTEXT) .. but for a SINGLE-BOOK. The where-exists stuff above is about getting the dbcontext loaded for several (cars,books,whatever).该链接是说“我如何检查 DBCONTEXT 中的存在/不存在)......但是对于单本。上面存在的东西是关于为几个(汽车,书籍,任何东西)加载 dbcontext。
Now, you can do some checking on whether to .Add (a Car) to the myDbContext, or "change some properties" of an existing.现在,您可以检查是否将(汽车)添加到 myDbContext 或“更改现有的某些属性”。 *** ***
But as the other link points out, you're gonna check for the values (the VA and the NC and the 2222-2222 and the 3333-3333), you gonna check the dbContext (items)但是正如另一个链接指出的那样,您将检查值(VA 和 NC 以及 2222-2222 和 3333-3333),您将检查 dbContext(项目)
Let me explain that answer's "trick".让我解释一下这个答案的“技巧”。
context.Entry(blog).State = blog.BlogId == 0 ?
EntityState.Added :
EntityState.Modified;
That is an old-"fairly standard" trick of using 0 as the "do i already exist or not".这是使用 0 作为“我是否已经存在”的古老“相当标准”的技巧。 with the "Car" from above, you don't have a single-surrogate-usually-primarykey thing like "BlogId".使用上面的“汽车”,您没有像“BlogId”这样的单一代理通常是主键。 with the car, you have 2 parts.对于汽车,您有 2 个部分。 so you'll have to check the myDbContext using the n-parts-of-the-compound-key to determine this.所以你必须使用 n-parts-of-the-compound-key 检查 myDbContext 来确定这一点。 it'll take a little experimentation to tweak your code.调整您的代码需要一些实验。
You will have to be aware if your context is long-lived (like a winforms desktop app) or your context is short-lived (like a rest-api).您必须知道您的上下文是长期存在的(如 winforms 桌面应用程序)还是短期的(如 rest-api)。
But that is a much deeper question.但这是一个更深层次的问题。 Here is a hint.这是一个提示。
https://docs.microsoft.com/en-us/ef/core/querying/tracking https://docs.microsoft.com/en-us/ef/core/querying/tracking
Then you gotta consider how hard your system is getting hit.然后你必须考虑你的系统受到多大程度的打击。 This could be a race-condition in a high hit system.这可能是高命中系统中的竞争条件。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.