将项目从 dotnet core 2.0 迁移到 3.1 并在 Entity Framework 上遇到一些问题
Migrating project from dotnet core 2.0 to 3.1 and having some problems on Entity Framework
我正在使用 DDD 构建一个项目。因此 update/add/delete 子实体的唯一方法是通过其父实体,当我使用 dotnet core 2.0 时这不是问题但现在我正在将项目迁移到 dotnet core 3.1 我收到以下错误:
Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
我有一个这样的客户class:
public class Client
{
/// <summary>
/// DDD Patterns comment Using a private collection field, better for DDD Aggregate's
/// encapsulation so Receptions cannot be added from "outside the AggregateRoot" directly to
/// the collection, but only through the method ClientAggrergateRoot.AddReception() which
/// includes behaviour.
/// </summary>
private readonly List<Reception> _receptions;
public Client(Guid id, string name, string url, string domainEmail)
{
Id = id;
Name = name;
Url = url;
DomainEmail = domainEmail;
_receptions = new List<Reception>();
}
protected Client()
{
_receptions = new List<Reception>();
}
public string Name { get; private set; }
public string Url { get; private set; }
public string DomainEmail { get; private set; }
public bool IsDeleted { get; private set; }
public DateTime CreatedAt { get; private set; }
public DateTime ModifiedAt { get; private set; }
public IReadOnlyCollection<Reception> Receptions => _receptions;
}
我有我的招待会class:
public class Reception
{
public Reception(Guid id, string name, string address, string noteToGuest, string noteToReceptionst,
string timeZone, Guid clientId)
{
Id = id;
Name = name;
Address = address;
ClientId = clientId;
}
private Reception()
{
}
public Guid ClientId { get; private set; }
public string Name { get; private set; }
public string Address { get; private set; }
}
这是客户端配置文件:
public class ClientEntityTypeConfiguration
: IEntityTypeConfiguration<Client>
{
public void Configure(EntityTypeBuilder<Client> builder)
{
builder.ToTable("Clients", BeWelcomeContext.CLIENT_SCHEMA);
builder.HasKey(c => c.Id);
var navigation = builder.Metadata.FindNavigation(nameof(Client.Receptions));
// DDD Patterns comment: Set as field (New since EF 1.1) to acces the Receptions
// collection property through its fields
navigation.SetPropertyAccessMode(PropertyAccessMode.Field);
}
}
以及接收配置文件:
public class ReceptionEntityTypeConfiguration
: IEntityTypeConfiguration<Reception>
{
public void Configure(EntityTypeBuilder<Reception> builder)
{
builder.ToTable("Receptions", BeWelcomeContext.CLIENT_SCHEMA);
builder.HasKey(r => r.Id);
builder.HasOne<Client>()
.WithMany(r => r.Receptions)
.IsRequired()
.HasForeignKey(r => r.ClientId);
}
}
在我进行项目迁移之前,它一直运行良好,如果我必须更改一些配置,我不知道发生了什么。
Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
您的数据库似乎阻止修改数据。查看您的日志,复制由 EF Core 创建的 SQL 查询并尝试在您的 DBMS 中 运行 它,也许您会得到更详细的错误。通常有一个触发器阻止执行操作。
这是 dot net 3.0 中的重大更改。
如果您使用 Guid 键并预生成它们(我正在做同样的 DDD 事情),那么 Ef 现在将其视为修改后的对象而不是新对象。
解决方案是关闭模型的密钥生成。
上面link有详细的解释。
但总而言之,您需要在 DbContext OnModelCreating
中进行此更改
modelBuilder
.Entity<Client>()
.Property(e => e.Id)
.ValueGeneratedNever();
如果模型派生自某些 class,例如具有 ID 属性 的实体,那么可能会使用更好的解决方法,
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public string Id { get; set; }
在父项上设置此项将在 class 之后应用它。
我正在使用 DDD 构建一个项目。因此 update/add/delete 子实体的唯一方法是通过其父实体,当我使用 dotnet core 2.0 时这不是问题但现在我正在将项目迁移到 dotnet core 3.1 我收到以下错误:
Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
我有一个这样的客户class:
public class Client
{
/// <summary>
/// DDD Patterns comment Using a private collection field, better for DDD Aggregate's
/// encapsulation so Receptions cannot be added from "outside the AggregateRoot" directly to
/// the collection, but only through the method ClientAggrergateRoot.AddReception() which
/// includes behaviour.
/// </summary>
private readonly List<Reception> _receptions;
public Client(Guid id, string name, string url, string domainEmail)
{
Id = id;
Name = name;
Url = url;
DomainEmail = domainEmail;
_receptions = new List<Reception>();
}
protected Client()
{
_receptions = new List<Reception>();
}
public string Name { get; private set; }
public string Url { get; private set; }
public string DomainEmail { get; private set; }
public bool IsDeleted { get; private set; }
public DateTime CreatedAt { get; private set; }
public DateTime ModifiedAt { get; private set; }
public IReadOnlyCollection<Reception> Receptions => _receptions;
}
我有我的招待会class:
public class Reception
{
public Reception(Guid id, string name, string address, string noteToGuest, string noteToReceptionst,
string timeZone, Guid clientId)
{
Id = id;
Name = name;
Address = address;
ClientId = clientId;
}
private Reception()
{
}
public Guid ClientId { get; private set; }
public string Name { get; private set; }
public string Address { get; private set; }
}
这是客户端配置文件:
public class ClientEntityTypeConfiguration
: IEntityTypeConfiguration<Client>
{
public void Configure(EntityTypeBuilder<Client> builder)
{
builder.ToTable("Clients", BeWelcomeContext.CLIENT_SCHEMA);
builder.HasKey(c => c.Id);
var navigation = builder.Metadata.FindNavigation(nameof(Client.Receptions));
// DDD Patterns comment: Set as field (New since EF 1.1) to acces the Receptions
// collection property through its fields
navigation.SetPropertyAccessMode(PropertyAccessMode.Field);
}
}
以及接收配置文件:
public class ReceptionEntityTypeConfiguration
: IEntityTypeConfiguration<Reception>
{
public void Configure(EntityTypeBuilder<Reception> builder)
{
builder.ToTable("Receptions", BeWelcomeContext.CLIENT_SCHEMA);
builder.HasKey(r => r.Id);
builder.HasOne<Client>()
.WithMany(r => r.Receptions)
.IsRequired()
.HasForeignKey(r => r.ClientId);
}
}
在我进行项目迁移之前,它一直运行良好,如果我必须更改一些配置,我不知道发生了什么。
Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
您的数据库似乎阻止修改数据。查看您的日志,复制由 EF Core 创建的 SQL 查询并尝试在您的 DBMS 中 运行 它,也许您会得到更详细的错误。通常有一个触发器阻止执行操作。
这是 dot net 3.0 中的重大更改。
如果您使用 Guid 键并预生成它们(我正在做同样的 DDD 事情),那么 Ef 现在将其视为修改后的对象而不是新对象。
解决方案是关闭模型的密钥生成。
上面link有详细的解释。
但总而言之,您需要在 DbContext OnModelCreating
modelBuilder
.Entity<Client>()
.Property(e => e.Id)
.ValueGeneratedNever();
如果模型派生自某些 class,例如具有 ID 属性 的实体,那么可能会使用更好的解决方法,
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public string Id { get; set; }
在父项上设置此项将在 class 之后应用它。