【问题标题】:EF Core Not Sending All Modified Fields for UpdateEF Core 未发送所有已修改字段进行更新
【发布时间】:2020-05-09 00:15:58
【问题描述】:

我正在做一个简单的更新(使用带有 SQL 后端的 EF Core 3.1.2)并且无法了解为什么一个字段无法发送到数据库。

我有一个更新调用,在那里我可以看到我想要发送的 DateModified 的值:

但是,使用 SQL Profiler,我可以看到这是实际发送的内容,并且 DateModified 字段根本没有发送到 SQL:

这是试图发送的对象:

public class AVO : BasePropertiesWithID
{
    //[Authorize(Policy = "AllEmployees")]
    [ForeignKey("DivisionID")]
    public int DivisionID { get; set; }
    [Required]
    public int AccountNumber { get; set; }
    [Required]
    public string CustomerName { get; set; }
    [Required]
    public string Comments { get; set; }
    public bool IsActive { get; set; }
    public DateTime? StartDate { get; set; }
    public DateTime? EndDate { get; set; }

    [UseFiltering]
    [UseSorting]
    public virtual Division Division { get; set; }
}

这是包含 DateModified 字段(未发送)和正在发送的 DateInserted 字段的基类:

    public class BasePropertiesWithID
{
    [Key]
    [Column(Order = 1)]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }

    [Required]
    [Column(Order = 9990)]
    [DefaultValue("autoProcess")]
    public string InsertedBy { get; set; }

    [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:MM/dd/yyyy}")]
    [Required]
    [Column(Order = 9991)]
    public DateTime DateInserted { get; set; }

    [Required]
    [Column(Order = 9992)]
    [DefaultValue("autoProcess")]
    public string ModifiedBy { get; set; }

    [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:MM/dd/yyyy}")]
    [Required]
    [Column(Order = 9993)]
    public DateTime DateModified { get; set; }

}

我已经使用这个基类很长时间了,没有遇到任何问题,也没有遇到过这种情况。我搜索信息没有成功,虽然我确实找到了这个Why is EF Core Update failing to update a modified column,但它对我没有帮助。

为什么一个字段甚至无法发送?谁能提供为什么或如何解决这个问题?谢谢!

编辑:如何将此实体添加到 EF

【问题讨论】:

  • 为了清楚起见,我相信你使用的是 ef-6 而不是核心......你应该这样说......
  • @Seabizkit 我正在使用 EF Core 3.1.2 进行说明
  • 对不起,我认为没有相关但 [Column(Order = 9992)] 在核心 github.com/dotnet/efcore/issues/11314 中不起作用。回到您的问题,最有趣的外观 100% 正确我的猜测是删除配置中的行... 这是用于 DataModfied 的 ,valueGeneratedOnAddOrUpdated... 看看会发生什么
  • 哇。谢谢(你的)信息。看起来像最近正在调查的问题。 12 天前添加了一种解决方法。我将深入挖掘并以我最终实施的内容做出回应。谢谢@Seabizkit!

标签: .net entity-framework


【解决方案1】:

为什么字段发送失败?

因为您将属性配置为在添加或更新时生成它的值:

指示 EF 在每次更新后从数据库中重新加载该值。要应用客户端更新,您必须在模型中将 SetAfterSaveBehavior 设置为 PropertySaveBehavior.Save,如下所示:

modelBuilder.Entity<Person>().Property(b => b.ModifiedAt).Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Save);

例如

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.SqlServer;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading.Tasks;

namespace EfCore3Test
{

    public class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public DateTime ModifiedAt { get; set; }
    }

    public class Db : DbContext
    {

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<Person>().Property(p => p.ModifiedAt).HasDefaultValueSql("getdate()").ValueGeneratedOnAddOrUpdate();

            modelBuilder.Entity<Person>().Property(b => b.ModifiedAt).Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Save);

        }
        private static readonly ILoggerFactory loggerFactory = LoggerFactory.Create(builder =>
        {
            builder.AddFilter((category, level) =>
               category == DbLoggerCategory.Database.Command.Name
               && level == LogLevel.Information).AddConsole();
        });


        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseLoggerFactory(loggerFactory)
                          .UseSqlServer("Server=.;database=EfCore3Test;Integrated Security=true",
                                        o => o.UseRelationalNulls());

            base.OnConfiguring(optionsBuilder);
        }
    }





    class Program
    {

        static void Main(string[] args)
        {


            using var db = new Db();

            db.Database.EnsureDeleted();
            db.Database.EnsureCreated();

            var p = new Person() { Name = "Fred" };
            db.Set<Person>().Add(p);
            db.SaveChanges();

            p.Name = "Fred2";
            p.ModifiedAt = DateTime.Now.AddDays(-7);
            db.Set<Person>().Update(p);
            db.SaveChanges();


        }
    }
  }
}

输出

info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (0ms) [Parameters=[@p2='?' (DbType = Int32), @p0='?' (DbType = DateTime2), @p1='?' (Size = 4000)], CommandType='Text', CommandTimeout='30']
      SET NOCOUNT ON;
      UPDATE [Person] SET [ModifiedAt] = @p0, [Name] = @p1
      WHERE [Id] = @p2;
      SELECT @@ROWCOUNT;

【讨论】:

  • 非常感谢大卫布朗。最初,@Seabizkit 让我找到了正确的方向并发现了许多问题/观点。我最终所做的只是将基本实体属性更改为 ValueGeneratedOnAdd ,因为我正在发送值并且它按预期工作;但所有这一切中最有价值的方面是更多地了解它是如何工作的,找出为什么 ValueGenerator 会以 null 出现,并能够创建 ValueGenerator 来做我真正想要它做的事情。我肯定地说这是一个可以澄清的文档问题。非常感谢你们!
猜你喜欢
  • 2017-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-16
  • 1970-01-01
  • 1970-01-01
  • 2012-08-04
  • 1970-01-01
相关资源
最近更新 更多