dotnet / dotnet/efcore

A delete/insert converted to a update allows changing property values that should not changed after insert

Đang mở
#33,653 0 bình luận 1 reaction 1 người được giao Được @AndriySvyryd nhận Xem trên GitHub
area-model-building area-save-changes
Ngôn ngữ chính
C#
Star
14.8k
Fork
3.4k
Chỉ số merge pull request
Chỉ số pull request đang chờ

Mô tả

Originally reported here: https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql/issues/1908
See #30705

The main issue here is that the application is marking an entity as Deleted, and then adding a new instance with the same key as Added. Because of #30705, this gets converted to an update containing this:

```sql
UPDATE [Item] SET [CreatedAt] = @p0, [UpdatedAt] = @p1
```

Before 7.0.3, the behavior was this:

```sql
UPDATE [Item] SET [UpdatedAt] = @p1
```

`UpdatedAt` is marked as `BeforeSaveBehavior` ignore.
`CreatedAt` is marked as `AfterSaveBehavior` ignore.

So, if we treat this as an update, then `UpdatedAt` should be sent, but `CreatedAt` should not.
On the other hand, if this remains a `delete` `insert`, then `CreatedAt` should be sent in the insert, and `UpdatedAt` should not.

Repro:

```C#
using var context = new StoreContext();
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();

var item = new Item { Id = "abc", CreatedAt = DateTime.Now.ToString() };
var store = new Store { CreatedAt = DateTime.Now.ToString(), Items = { item }};
context.Add(store);
await context.SaveChangesAsync();
context.ChangeTracker.Clear();

store = await context.Stores.Include(e => e.Items).SingleAsync();

store.CreatedAt = "X";
store.UpdatedAt = "Y";

store.Items = new List()
{ new() { Id = item.Id, CreatedAt = "A", UpdatedAt = "B" } };

// Doing the store update like this instead does not result in the issue:
// store.Items.First().CreatedAt += "+";
// store.Items.First().UpdatedAt += "+";

context.SaveChanges();

public class Item
{
public string Id { get; set; } = null!;
public int StoreId { get; set; }

public string? CreatedAt { get; set; }
public string? UpdatedAt { get; set; }
}

public class Store
{
public int StoreId { get; set; }
public List Items { get; set; } = new();

public string? CreatedAt { get; set; }
public string? UpdatedAt { get; set; }
}

public class StoreContext : DbContext
{
public DbSet Stores => Set();

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) =>
optionsBuilder
.LogTo(Console.WriteLine, LogLevel.Information)
.UseSqlServer(
"Data Source=localhost;Database=BuildBlogs;Integrated Security=True;Trust Server Certificate=True;ConnectRetryCount=0");

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity(b =>
{
b.Property(x => x.CreatedAt).Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Ignore);
b.Property(x => x.UpdatedAt).Metadata.SetBeforeSaveBehavior(PropertySaveBehavior.Ignore);
});

modelBuilder.Entity(b =>
{
b.Property(x => x.CreatedAt).Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Ignore);
b.Property(x => x.UpdatedAt).Metadata.SetBeforeSaveBehavior(PropertySaveBehavior.Ignore);
});
}
}
```

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.