Entity Framework 写入上下文而非数据库
Entity Framework writes in Context but not Database
我们在 C# 中基于 EF 6.2.0 的应用程序使用 UnitOfWork 方法,使用 SQL Server 2017 Express (14.0.1000) 数据库后端。
我们从 DbContext
继承的 OwnContext.cs
应该自动填充字段 Id
、ChangedDate
和 ChangedUser
,这是我们数据库中每个实体的一部分型号:
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.State
是 EntityState.Modified
并且 countChanges
return 值是 1 并且 item.Entity
中的值似乎都是正确的。
如果查询对象,新值是可见的,但数据库中的值不会改变,所以如果我处理我的上下文,旧值将重新出现。
真正令人困惑的是,我在 ui 中更改的字段值进行测试 是 在数据库中更改,但字段 ChangedDate
.
为什么?
这是一个实体 class 和配置的示例,由 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();
}
对应table的SQLDDL:
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
您需要调用context.savechanges将数据保存到db
此时,更改跟踪器收到的实体对象上的 属性 更改与 DTO 无关。您需要通过 DbEntityEntry.CurrentValues
属性 应用更改。
item.CurrentValues["ChangedDate"] = DateTime.Now;
我们在 C# 中基于 EF 6.2.0 的应用程序使用 UnitOfWork 方法,使用 SQL Server 2017 Express (14.0.1000) 数据库后端。
我们从 DbContext
继承的 OwnContext.cs
应该自动填充字段 Id
、ChangedDate
和 ChangedUser
,这是我们数据库中每个实体的一部分型号:
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.State
是 EntityState.Modified
并且 countChanges
return 值是 1 并且 item.Entity
中的值似乎都是正确的。
如果查询对象,新值是可见的,但数据库中的值不会改变,所以如果我处理我的上下文,旧值将重新出现。
真正令人困惑的是,我在 ui 中更改的字段值进行测试 是 在数据库中更改,但字段 ChangedDate
.
为什么?
这是一个实体 class 和配置的示例,由 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();
}
对应table的SQLDDL:
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
您需要调用context.savechanges将数据保存到db
此时,更改跟踪器收到的实体对象上的 属性 更改与 DTO 无关。您需要通过 DbEntityEntry.CurrentValues
属性 应用更改。
item.CurrentValues["ChangedDate"] = DateTime.Now;