代码之家  ›  专栏  ›  技术社区  ›  Edward Tanguay

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

  •  3
  • Edward Tanguay  · 技术社区  · 7 年前

    我正在开发一个使用实体框架的asp.net mvc应用程序。我想换个场地 CreatedOn Users 表。

    以下代码

        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”,但它不会改变 创建 字段。

    我认为 创建 字段在某个地方被赋予了一些特殊的状态和功能,这些状态和功能在创建记录时用时间戳填充字段,并防止随后对其进行更改。

    我在代码中找不到它执行此操作的位置,因此我假设它位于实体框架模型、设置等中的某个位置。

    我在哪里可以找到它被设置在哪里,以及如何在它被设置之后更改它?

    附录

    例如,我在 <EntityType Name="Users"> 线路 <Property Name="CreatedOn" Type="datetime" Nullable="false" StoreGeneratedPattern="Computed" /> 把它改成 <Property Name="CreatedOn" Type="datetime" Nullable="false" /> 但它仍然将日期计算为datetime,并且不会更改它。

    输出原始sql,我在 update 声明,它离开了 创建 out:我的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)
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   Dave R.    7 年前

    这很可能是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关系图的属性页中 创建 字段,没有任何更改。

    使用以下代码添加几行:

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

    表中应按预期设置当前日期和时间。

    正如你所发现的,如果你试图 创建 手动插入新行时,由于SQL Server约束,此操作将不起作用。例如:

    db.DateDefaultTests.Add(new DateDefaultTest
    {
         SomeField = "Pears",
         CreatedOn = DateTime.UtcNow.AddHours(1)
    });
    

    将导致设置无意义的“0001-01-01”日期。

    如果要设置 创建 明确地。为此:

    db.DateDefaultTests
        .Where(x => x.SomeField == "Bananas")
        .First()
        .CreatedOn = DateTime.UtcNow.AddDays(-1);
    db.SaveChanges();
    

    如果这不适用于你的情况,我建议你:

    • 在SQL Server中检查列以确保不计算该值
    • 重新生成模型
    • 确认代码中没有可能影响实体保存时的值的ef重写

    对于我说ef不会更新默认列的评论,我深表歉意。这是不正确的,仅适用于初始插入。

    更新-所需设置:

    SQL Server CreatedOn Settings

    EDMX CreatedOn Settings