【问题标题】:Entity Framework writes in Context but not Database实体框架写入上下文而不是数据库
【发布时间】:2018-07-23 07:54:32
【问题描述】:

我们将 UnitOfWork 方法用于基于 C# 中的 EF 6.2.0 和 SQL Server 2017 Express (14.0.1000) 数据库后端的应用程序。

我们的 OwnContext.cs 继承自 DbContext 应该自动填充字段 IdChangedDateChangedUser,这是我们 db 模型中每个实体的一部分:

public partial class OwnContext : DbContext {

    public override int SaveChanges()
    {
        bool hasChanges = false;

        this.ChangeTracker.DetectChanges();

        #region Fill Created, Changed

        foreach (var item in this.ChangeTracker.Entries()
            .Where(x => (x.State == EntityState.Added || x.State == EntityState.Modified || x.State == EntityState.Deleted)))
        {
            if (item.State == EntityState.Deleted)
            {
                hasChanges = true;
            }
            else
            {
                // Id
                PropertyInfo pI = item.Entity.GetType().GetProperty("Id");
                if (pI != null)
                {
                    Guid id = (Guid)pI.GetValue(item.Entity, null);
                    if ((Guid)id == Guid.Empty)
                    {
                        id = Guid.NewGuid();
                        pI.SetValue(item.Entity, id);
                    }
                }

                DateTime now = DateTime.Now;

                // Timestamp & User
                pI = item.Entity.GetType().GetProperty("CreatedDate");
                if (pI != null)
                {
                    var date = pI.GetValue(item.Entity, null);
                    // Only if empty on new records
                    if (date == null || date.Equals(DateTime.MinValue))
                    {
                        pI.SetValue(item.Entity, now);
                        pI = item.Entity.GetType().GetProperty("CreatedUser");
                        if (pI != null)
                        {
                            pI.SetValue(item.Entity, Environment.UserName); 
                        }
                    }
                    pI = item.Entity.GetType().GetProperty("ChangedDate");
                    if (pI != null)
                    {
                        pI.SetValue(item.Entity, now);
                    }
                    pI = item.Entity.GetType().GetProperty("ChangedUser");
                    if (pI != null)
                    {
                        pI.SetValue(item.Entity, Environment.UserName); 
                    }
                }

                hasChanges = true;

            }

        }

        #endregion

        int countChanges = 0;

        if (hasChanges)
        {
            // Call SaveChanges Method from Context;
            try
            {
                countChanges = base.SaveChanges();
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }
        return countChanges;
    }
}

适用于完美运行的新记录,但不适用于修改后的记录。

ChangedDate 字段中的新日期时间值仅出现在上下文中,但不会写入数据库。 如果我单步执行代码,我会看到 item.StateEntityState.Modified 并且 countChanges 返回值为 1 并且 item.Entity 中的值一切似乎都是正确的。 如果查询对象,新值是可见的,但数据库中的值不会改变,所以如果我处理我的上下文,旧值将重新出现。

真正令人困惑的是,我在 ui 中更改的字段值以测试它 在 db 中更改,而不是字段 ChangedDate

为什么?

这是一个实体类和配置的示例,由 Devarts Entity Devloper 创建:

public partial class Abo {

    public Abo()
    {
        OnCreated();
    }

    #region Properties

    public virtual global::System.Guid Id
    {
        get;
        set;
    }

    // ...

    public virtual global::System.Nullable<System.DateTime> ChangedDate
    {
        get;
        set;
    }

    public virtual global::System.Nullable<System.DateTime> CreatedDate
    {
        get;
        set;
    }

    public virtual string CreatedUser
    {
        get;
        set;
    }

    public virtual string ChangedUser
    {
        get;
        set;
    }
}   


public partial class AboConfiguration : EntityTypeConfiguration<Abo>
{

    public AboConfiguration()
    {
        this
            .HasKey(p => p.Id)
            .ToTable("Abos", "dbo");
        // Properties:
        this
            .Property(p => p.Id)
                .IsRequired()
                .HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None)
                .HasColumnType("uniqueidentifier");

        // ...
        this
            .Property(p => p.CreatedDate)
                .HasColumnType("datetime");
        this
            .Property(p => p.ChangedDate)
                .HasColumnType("datetime");
        this
            .Property(p => p.CreatedUser)
                .HasMaxLength(32)
                .HasColumnType("varchar");
        this
            .Property(p => p.ChangedUser)
                .HasMaxLength(32)
                .HasColumnType("varchar");

        OnCreated();
    }

    partial void OnCreated();

}

对应表的SQL DDL:

CREATE TABLE [dbo].[Abos](
    [Id] [uniqueidentifier] NOT NULL,
/* .. */
    [ChangedDate] [datetime] NULL,
    [CreatedDate] [datetime] NULL,
    [ChangesUser] [varchar](32) NULL,
    [CreatedUser] [varchar](32) NULL
 CONSTRAINT [PK_dbo.Abos] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

【问题讨论】:

  • 查看错误的数据库?使用内部数据库服务器时的一个已知问题是,网站运行的 COPY 在每次项目启动时都会重置。
  • 我们使用 app.config 中的 ConnectString 来建立数据库连接。 connectionString="Data Source=localhost\SQLEXPRESS; Initial Catalog=Abo; Integrated security=true;MultipleActiveResultSets=True;" 如何使用错误的数据库服务器?顺便提一句。它是一个 WinForms 应用程序。
  • 我在这里看不到任何工作单元。 UoW 意味着创建一个新的上下文,用它做一些事情,调用SaveChanges() 并处理它。这看起来像是试图通过...重新实现自动生成的 ID 功能来绕过 SaveChanges(为什么?)?所有这些东西都已经在 EF 中可用,可以通过属性或上下文的配置方法轻松配置。您是否尝试向实体添加审计列
  • context的配置在哪里? entity 中是否存在ChangedDate 属性?它是否在配置中映射?为什么要在 client 中实现审计属性,而不是在服务器上使用触发器和默认约束?
  • 我猜此时,更改跟踪器收到的实体对象上的属性更改与 DTO 无关。您是否尝试通过“item.CurrentValues”应用更改?

标签: c# entity-framework-6 sql-server-2017-express


【解决方案1】:

此时,更改跟踪器接收到的实体对象上的属性更改与 DTO 无关。您需要改为通过 DbEntityEntry.CurrentValues 属性应用更改。

item.CurrentValues["ChangedDate"] = DateTime.Now;

【讨论】:

    【解决方案2】:

    需要调用 context.savechanges 将数据保存到 db

    【讨论】:

    • 请看最后一次尝试..catch 那里你会发现base.SaveChanges()
    • 谢谢,错过了,但它不应该是 base.SaveChanges(),应该是 this.SaveChanges(),因为正在跟踪的表是在这个上下文中,而不是在基本上下文中。
    • 我不这么认为,因为我的方法应该覆盖上下文中的Context.SaveChanges(),但最后我必须用base.SaveChanges() 调用它。你打电话给this.SaveChanges() 的建议会反复调用我自己的方法,这是我不想要的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-12
    • 2014-04-01
    相关资源
    最近更新 更多