gpt4 book ai didi

c# - 乐观并发

转载 作者:太空狗 更新时间:2023-10-29 20:39:04 25 4
gpt4 key购买 nike

我有一个包含多个链接实体的 Entity Framework 项目。因为它一次被多个用户使用,所以我为可能被多个用户同时编辑的实体设置了一个 RowVersion-Field。不幸的是,我现在每次尝试保存链接到现有实体的新实体时都会收到 OptimisticConecurrencyException

Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=472540 for information on understanding and handling optimistic concurrency exceptions.

现在的问题是这个错误并没有给出任何关于错误真正所在的指针。它可能是同时修改了基础模型,新模型或其他原因可能存在验证错误。

我用来添加新实体的代码如下:

using (ctx = new DbContext())
{
try
{
ctx.Samples.Add(model);
ctx.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
LogManager.HandleException(ex.InnerException);
}
}

model 是我要添加到数据库的模型

编辑:如上所示,我修改了代码以忽略基础模型的更新。此外,我已经通过以下方式验证:

ctx.Database.log = s => Debug.Write(s);

只有一个插入语句被发送到数据库,而不是一个额外的更新语句。

INSERT [dbo].[Samples]([IDSample], [ModificationDate], [IDUser])
VALUES (@0, @1, @2)
SELECT [RowVersion]
FROM [dbo].[Samples]
WHERE @@ROWCOUNT > 0 AND [IDSample] = @0 AND [ModificationDate] = @1

如果我更新一个实体并且 rowversion 列不匹配,我会理解异常,但在这种情况下它是一个全新的实体。有没有办法查看其中一个属性是否格式错误?

编辑2:

我现在使用 DateTime.Today 而不是 DateTime.Now 而不是仅仅调整毫秒数。似乎 ModificationDate 上的 datetime2(4) 存在一些问题。我已经确保 ModificationDate 被截断为 4 毫秒,因此应该没有解析错误。

编辑3:

切换回 DateTime.Now 并调整毫秒数后,它停止工作,并且不再将实体插入到数据库中。这可能是由于 sql server 在匹配基于毫秒值的实体时出现问题。我使用一些虚构的值执行了上面看到的 EF 生成的 SQL,它通过了,尽管在某些情况下查询没有返回 rowversion-value。就 Entity Framework 而言,客户端会将此解释为 0 行的返回值,因此调用并发异常。 (还应注意,ModificationDate 与 IDSample 一起是实体的主键。)

编辑4:

我现在使用 DateTime.Today 然后添加所需的精度,这对我有用。这可以标记为已解决。 (尽管我本以为 EF 可以自行处理日期时间格式转换:/)

最佳答案

我的问题是您在哪里添加日期时间?您正在创建太多步骤来解决这个问题。创建日期时间、修改日期时间等。

如果您的实体继承自具有映射属性的基类,请在 SaveChanges() 的 DbContext 覆盖中执行并发添加/更新。

这是一个例子:(没有优化语法编写)

public abstract class EntityBase
{
public int Id {get; set;}
public DateTime CreationDate {get; set;}
public DateTime? ModifyDate {get; set;}
public string VersionHash {get; set;}
}
public static class EntityBaseExtensions
{
public static void MyBaseEntityMapping<T>(this EntityTypeConfiguration<T> configuration) where T : EntityBase
{
configuration.HasKey(x => x.Id);
configuration.Property(x => x.CreationDate)
.IsRequired();
configuration.Property(x => x.ModifyDate)
.IsOptional();
configuration.Property(x => x.VersionHash).IsConcurrencyToken();
}
}
public class MyEntity : EntityBase
{
public string MyProperty {get; set;}
}
public class MyEntityMapping : EntityTypeConfiguration<MyEntity>
{
public MyEntityMapping()
{
this.MyBaseEntityMapping();
Property(x=>x.MyProperty).IsRequired();
}
}

public class MyContext : DbContext
{
....
public override int SaveChanges()
{
this.ChangeTracker.DetectChanges(); //this forces EF to compare changes to originals including references and one to many relationships, I'm in the habit of doing this.

var context = ((IObjectContextAdapter)this).ObjectContext; //grab the underlying context
var ostateEntries = context.ObjectStateManager.GetObjectStateEntries(EntityState.Modified | EntityState.Added); // grab the entity entries (add/remove, queried) in the current context

var stateEntries = ostateEntries.Where(x => x.IsRelationship == false && x.Entity is EntityBase); // don't care about relationships, but has to inherit from EntityBase

var time = DateTime.Now; //getting a date for our auditing dates

foreach (var entry in stateEntries)
{
var entity = entry.Entity as EntityBase;
if (entity != null) //redundant, but resharper still yells at you :)
{
if (entry.State == EntityState.Added) //could also look at Id field > 0, but this is safe enough
{
entity.CreationDate = time;
}
entity.ModifyDate = time;
entity.VersionHash = Guid.NewGuid().ToString().Replace("-", "").Substring(0, 10); //this an example of a simple random configuration of letters/numbers.. since the query on sql server is primarily using the primary key index, you can use whatever you want without worrying about query execution.. just don't query on the version itself!
}
}
return base.SaveChanges();
}
....
}

关于c# - 乐观并发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30255309/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com