![](/img/trans.png)
[英]Entity Framework Core is trying to insert duplicated records when SaveChanges() is called
[英]Force Entity Framework Core to reload some fields after SaveChanges is called
我有一個項目使用 Entity Framework Core 在 Postgres 的表中插入/更新記錄,並且我遇到了 C# 中某些值的數值精度高於 Postgres 的數值精度的情況。
例如,我可能具有數數0.99878
內存在物業類型double
在C#中,但是當我保存這個值,也可能被存儲在Posgres為0.9988
,而不是,這是完全正常和預期。
實體框架不知道 Postgres 在存儲這個數字時做了什么,一切似乎都很好,但實際上我在內存中的數字是不正確的,除非我手動告訴 EF 刷新實體。
我無法提高數據庫中的精度,但我想避免在每次SaveChanges
后手動刷新實體
如何告訴 Entity Framework Core 在SaveChanges
后自動刷新某些字段?
我嘗試設置.ValueGeneratedOnAddOrUpdate
但這忽略了我在內存中的值。
默默地失去精度肯定是一個問題。 對於我自己的用例,涉及跟蹤貨幣,我發現這種行為是不可接受的。 為了將代碼重復保持在最低限度,我引入了一個驗證屬性,強制模型中的每個小數都有它,用它來定義數據庫中的列類型,並在保存之前重新驗證每個修改過的對象。
[AttributeUsage(AttributeTargets.Property)]
public class PrecisionAttribute : ValidationAttribute
{
public PrecisionAttribute(int precision, int scale)
{
Precision = precision;
Scale = scale;
}
public int Precision { get; set; }
public int Scale { get; set; }
public override bool IsValid(object value)
{
if (value is decimal val)
{
if (val == 0)
return true;
var sqlDec = new SqlDecimal(val);
try
{
return (sqlDec == SqlDecimal.ConvertToPrecScale(sqlDec, Precision, Scale)).Value;
}
catch (Exception)
{
return false;
}
}
var dec = value as decimal?;
return !dec.HasValue || IsValid(dec.Value);
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (IsValid(value))
return ValidationResult.Success;
return new ValidationResult($"'{value}' is not a valid {validationContext.DisplayName}", new string[] { validationContext.MemberName });
}
public void Apply(IMutableProperty property) => property.SetColumnType($"numeric({Precision},{Scale})");
}
// ... DbContext ...
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//...
foreach (var table in modelBuilder.Model.GetEntityTypes())
{
foreach (var col in table.GetProperties())
{
var precision = col.PropertyInfo?.GetCustomAttribute<PrecisionAttribute>() ?? col.FieldInfo?.GetCustomAttribute<PrecisionAttribute>();
if (precision != null)
precision.Apply(col);
else if(col.ClrType == typeof(decimal) || col.ClrType == typeof(decimal?))
throw new Exception($"Decimal column {table.ClrType.Name}.{col.Name} doesn't have a precision!");
}
}
}
public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default(CancellationToken))
{
PreSave();
return await base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}
public override int SaveChanges(bool accept) {
PreSave();
return base.SaveChanges(accept);
}
private void PreSave()
{
if (!ChangeTracker.HasChanges())
return;
var serviceProvider = this.GetService<IServiceProvider>();
var items = new Dictionary<object, object>();
foreach (var entry in ChangeTracker.Entries())
{
switch (entry.State)
{
case EntityState.Added:
case EntityState.Modified:
var context = new ValidationContext(entry.Entity, serviceProvider, items);
Validator.ValidateObject(entry.Entity, context, true);
break;
}
}
}
我在 Entity Framework 開源存儲庫中詢問過,此功能不存在(至少在當前的 .NET 5 版本中今天如此)並已添加到待辦事項中以供考慮。
支持存儲生成的值,這些值在同一命令中既寫入數據庫又從數據庫中讀回
https://github.com/dotnet/efcore/issues/23196#issuecomment-723494947
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.