C# 为什么我不能通过实体框架覆盖某个字段?
我正在开发一个使用实体框架的ASP.NETMVC应用程序。我想更改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
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覆盖,这可能会影响实体保存时的值
用户是来自您的代码还是来自ASP.Net标识?您使用的是哪个版本的EF?类已生成,即有“此代码是从模板生成的…”的通知,但我没有设置它。在该类中,我没有看到定义
public System.DateTime CreatedOn{get;set;}
上方的属性。在我的packages.config
文件中,我找到了
。您是否尝试在DbContext
类中查找,以查看其中是否发生了一些事情?您还尝试过将实体标记为已修改db.Entry(theUser.State=System.Data.entity.EntityState.modified调用db.SaveChanges()之前的代码>
?我们有一个MainDB
类,它继承DbContext并覆盖SaveChanges,但是没有任何类专门处理Users
表中的CreatedOn
。我添加了db.Entry(theUser.State=System.Data.Entity.EntityState.Modified代码>但它像以前一样保存:对CreatedOn
值没有更改。db.Database.Log=s=>System.Diagnostics.Debug.WriteLine只要项目在Debug
模式下运行,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