C# 为什么我不能通过实体框架覆盖某个字段?

C# 为什么我不能通过实体框架覆盖某个字段?,c#,entity-framework,C#,Entity Framework,我正在开发一个使用实体框架的ASP.NETMVC应用程序。我想更改Users表中的CreatedOn字段 下面的代码 using (var db = new MainDB()) { var theUser = db.Users.Single(u => u.LoginName == model.User.LoginName); theUser.CreatedOn = new DateTime(2017, 1, 1); // this do

我正在开发一个使用实体框架的ASP.NETMVC应用程序。我想更改
Users
表中的
CreatedOn
字段

下面的代码

    using (var db = new MainDB())
    {   
        var theUser = db.Users.Single(u => u.LoginName == model.User.LoginName);
        theUser.CreatedOn = new DateTime(2017, 1, 1); // this does not save
        theUser.CF20 = "test20";
        db.SaveChanges();   
    }
    
将字段
CF20
更改为“test20”,但不会更改
CreatedOn
字段

我假设
CreatedOn
字段在某个地方被赋予了一些特殊的状态和功能,这些状态和功能在创建记录时用时间戳填充它,并防止它在以后被更改

我在代码中找不到它的位置,所以我假设它在实体框架模型、设置等中的某个地方

在哪里可以查看设置位置以及设置后如何更改?

补遗 例如,我在
下的.edmx文件中找到了
行,并将其更改为
,但它仍然将日期计算为datetime,并且不会更改它

输出原始SQL时,我看到在
update
语句中,它将
CreatedOn
保留在外:我的SQL输出显示:

UPDATE [dbo].[Users]
SET [LoginName] = @0,
    [Password] = @1,
    [PasswordSalt] = @2,
    [LastLoginIP] = NULL,
    [Status] = @3,
    [Email] = @4,
    [FailedLoginAttempts] = NULL,
    [CF01] = NULL,
    [CF02] = NULL,
    [CF03] = NULL,
    [CF04] = NULL,
    [CF05] = NULL,
    [CF06] = NULL,
    [CF07] = NULL,
    [CF08] = NULL,
    [CF09] = NULL,
    [CF10] = NULL,
    [LanguageID] = @5,
    [CF11] = NULL,
    [CF12] = NULL,
    [CF13] = NULL,
    [CF14] = NULL,
    [CF15] = NULL,
    [CF16] = NULL,
    [CF17] = NULL,
    [CF18] = NULL,
    [CF19] = @6,
    [CF20] = @7,
    [MustChangePassword] = NULL
WHERE ([ID] = @8)

这很可能是SQL Server中的一个计算列,因此在代码中没有实际设置它的地方—在最初添加行时,它是在服务器上完成的。EF将不在更新查询中包括计算列,并将在更新查询后读回列,以便从数据存储中加载可能更新的值

讨论后更新:

这是一个最小的解决方案,默认值会根据需要正确更新

首先在SQL Server上创建一个新表:

CREATE TABLE [dbo].[DateDefaultTest](
    [AnId] [int] IDENTITY(1,1) NOT NULL,
    [CreatedOn] [datetime2](7) NOT NULL,
    [SomeField] [nvarchar](50) NULL,
 CONSTRAINT [PK_DateDefaultTest] PRIMARY KEY CLUSTERED 
(
    [AnId] 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

ALTER TABLE [dbo].[DateDefaultTest] ADD  CONSTRAINT [DF_DateDefaultTest_CreatedOn]  DEFAULT (getutcdate()) FOR [CreatedOn]
GO
它有一个ID字段作为自动递增主键,一个字符串字段和我们感兴趣的
CreatedOn
字段。我们添加了一个默认约束,将其设置为当前UTC日期和时间

接下来,创建一个控制台应用程序,通过NuGet添加EF,并按照常规设置DbContext。我已经调用了我的上下文
DefaultTestEntities

实体生成的代码如下所示:

public partial class DateDefaultTest
{
    public int AnId { get; set; }
    public System.DateTime CreatedOn { get; set; }
    public string SomeField { get; set; }
}
在EF图的
CreatedOn
字段的属性页中,没有任何更改

使用以下代码添加两行:

using (var db = new DefaultTestEntities())
{
    db.DateDefaultTests.Add(new DateDefaultTest
    {
         SomeField = "Bananas"
    });
    db.DateDefaultTests.Add(new DateDefaultTest
    {
         SomeField = "Apples",
    });

    db.SaveChanges();
}
这些应显示在表中,并按预期设置当前日期和时间

正如您所发现的,如果在插入新行时尝试手动设置
CreatedOn
,由于SQL Server约束,这将不起作用。例如:

db.DateDefaultTests.Add(new DateDefaultTest
{
     SomeField = "Pears",
     CreatedOn = DateTime.UtcNow.AddHours(1)
});
将导致设置无意义的“0001-01-01”日期

如果要显式设置
CreatedOn
,则必须更新现有行。为此:

db.DateDefaultTests
    .Where(x => x.SomeField == "Bananas")
    .First()
    .CreatedOn = DateTime.UtcNow.AddDays(-1);
db.SaveChanges();
如果这不适用于您的情况,我建议您:

  • 检查SQL Server中的列以确保未计算该值
  • 重新生成您的模型
  • 确认代码中没有EF覆盖,这可能会影响实体保存时的值
对于我说EF不会更新默认列的评论,我深表歉意。这是不正确的,仅适用于初始插入

更新-所需设置:


用户是来自您的代码还是来自ASP.Net标识?您使用的是哪个版本的EF?类已生成,即有“此代码是从模板生成的…”的通知,但我没有设置它。在该类中,我没有看到定义
public System.DateTime CreatedOn{get;set;}
上方的属性。在我的
packages.config
文件中,我找到了
。您是否尝试在
DbContext
类中查找,以查看其中是否发生了一些事情?您还尝试过将实体标记为已修改
db.Entry(theUser.State=System.Data.entity.EntityState.modifieddb.SaveChanges()之前的代码>
?我们有一个
MainDB
类,它继承DbContext并覆盖SaveChanges,但是没有任何类专门处理
Users
表中的
CreatedOn
。我添加了
db.Entry(theUser.State=System.Data.Entity.EntityState.Modified但它像以前一样保存:对
CreatedOn
值没有更改。
db.Database.Log=s=>System.Diagnostics.Debug.WriteLineDebug
模式下运行,code>就应该在输出窗口中输出。确保在“输出”窗口中,从下拉列表中选择“显示来自:调试的输出”。我刚刚使用了
db.Database.Log=s=>System.Diagnostics.Debug.WriteLine
,可以在输出窗口中的
默认值或绑定下查看原始sql查询。对于此列,我发现
(getdate())
。如何使其仅在创建时计算,否则可以更改?@EdwardTanguay默认值将阻止EF更新此列。您可以删除默认值并创建一个插入触发器。如果触发器不是选项,您可以删除默认值并覆盖EF代码中的
SaveChanges()
。然后,您可以在添加
实体状态时设置初始值,但我可以使用SQL覆盖此默认值,例如
更新用户集CreatedOn=GETDATE(),其中id=44
。但是,只有在.edmx文件中设置了
StoredGeneratedPattern=“None”
而不是
之后,我才能通过实体框架覆盖它。但如果我这样做,那么Entity Framework出于某种原因将不允许SQL Server应用默认值,即新记录对此值具有
0001-01-01 00:00:00.0000000
。问题是,即使我在.edmx文件中为此列指定了
StoredGeneratedPattern=“None”
,Entity Framework仍然存在,发送一个值,然后覆盖数据库默认值:
INSERT[dbo].[Users]([LoginName],[Password],…,[CreatedOn])值(@0,@1,…,@7),其中@7='0001-01-01 00:00:0