问题描述

今天下午(看现在这时间,应该是昨天下午了哈),园友 choon 写了这样一篇博文《关于有默认值的字段在用EF做插入操作时的思考》。

博文内容主要记录的是 choon 使用 EF 做数据插入与更新时,字段默认值的问题,这个问题我们平常应该都会遇到,但是,最后博文内容包括评论,并没人能给出一个准确的答案,真是很可惜(知识点的博文都是一侃一大堆,而这些实际项目遇到的问题却回答不上来,又有什么用呢,哎。。。)。详细内容请查看上面的博文,这边我再简单叙述下:

数据库有一个 Users 表,表中有一个 CreateDate 字段,我们希望使用 EF 的时候,插入 User 数据,不需要插入 CreateDate 的值,而是通过默认值生成。

  1. CreateDate 字段为 null:使用 EF 的 ADD 操作(没有给 User 对象赋予 CreateDate 的值),插入的结果是 CreateDate 值为 null。
  2. CreateDate 字段不为 null:还是按照上面的操作,插入 User 报错。

choon 最后给出的解决方式是:

<Property Name="CreateDate" Type="datetime" Nullable="false" StoreGeneratedPattern="Computed" />

后来,choon 又补充这样实现的两个问题(看过下面的内容,你就知道为什么会出现这两个问题了):

  1. 如果将 StoreGeneratedPattern 值设置为 Identity,只要一修改 CreateDate 字段就会抛异常;
  2. 如果把 StoreGeneratedPattern 值设置为 Computed 不会抛异常,但值仍然没有被修改,即使你写了 user.CreateDate = "xxx"。

问题分析

为了方面理解,我按照当时实现的步骤叙述下,因为我喜欢 EF 的 CodeFirst 模式,所以这边我就用它来做演示,看一下示例代码:

using System;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;namespace CodeFirstDemo
{class Program{static void Main(string[] args){using (var db = new ProductContext()){var product = new Product { Name = "xishuai" };db.Products.Add(product);db.SaveChanges();Console.WriteLine("success");Console.ReadKey();}}}public class Product{[Key]public int ID { get; set; }public string Name { get; set; }public DateTime? CreateTime { get; set; }}public class ProductContext : DbContext{public DbSet<Product> Products { get; set; }}
}

这是我们一般的实现方式,注意这段代码:var product = new Product { Name = "xishuai" }; 我并没有给 CreateTime 进行赋值,为了可以使数据库生成成功,我还把 CreateTime 设置为 null(DateTime?),但是运行的结果是:数据库生成了,却只有 ID 和 Name 字段,而且添加数据失败:

异常信息:“由于表 'Products' 中不存在列 'CreateTime',ALTER TABLE ALTER COLUMN 失败。”,什么原因呢?主要是没有指定 CreateTime 属性(Attribute),比如[Required],但是我们发现 Name 也没有指定啊,为什么它却可以生成数据库列?因为我们在 Add 的时候指定 Name 的值了,这样 EF 会自动识别这些字段进行生成列。

我们可以先把数据库生成一下,然后再进行实验,可以暂时把添加数据代码改为:var product = new Product { Name = "xishuai", CreateTime = DateTime.Now };,这样数据库就可以成功生成了,之后再还原一下,我们按照 choon 的配置,做下面类似的操作:

        [DatabaseGenerated(DatabaseGeneratedOption.Computed)]public DateTime? CreateTime { get; set; }

上面添加的属性配置和 choon 在 config 中的配置是一样的,只不过这个场景是 CodeFirst 下。毫无疑问,这样添加数据像 choon 一样,还是会无效果或抱异常(没有赋值 CreateTime),那究竟是什么问题呢?我们再看一下 StoreGeneratedPattern 的枚举值(MSDN详情):

  • None:一个值,指示它不是服务器生成的属性。这是默认值。如果没有StoreGeneratedPattern属性,其值就默认为None.
  • Identity:执行插入时生成一个值,但在执行更新时保持不变。
  • Computed:执行插入和更新时都将生成一个值。

Identity 是什么意思?其实是标识键的意思,也就是我们常说的自增键,如果我们把上面示例中 CreateTime 的数据类型改为 int,配置还是原来的配置,但是数据识可以添加的,园中也有人做了一个示例,详情请访问:Entity Framework 数据生成选项 DatabaseGenerated。

在 MSDN 中也又相应的示例说明,我贴一下关于这一点的总结(MSDN详情):

You read above that by default, a key property that is an integer will become an identity key in the database. That would be the same as setting DatabaseGenerated to DatabaseGenerationOption.Identity. If you do not want it to be an identity key, you can set the value to DatabaseGenerationOption.None.

英语不太好,请自行理解,说了这么多,难道没有解决方式吗?当然会有,只是你比较懒而已,google 搜索:“code first datetime default” 、“databasegenerated datetime” 或 “An error occurred while updating the entries. See the inner exception for details” 关键字,你就会发现答案。

解决方案

首先,Product 中的 CreateTime 属性,还是之前的配置:

        [DatabaseGenerated(DatabaseGeneratedOption.Computed)]public DateTime? CreateTime { get; set; }

我们要做的是使用 CodeFirst 迁移(怎么迁移?请查看:初试Code First(附Demo)),先输入命令“Enable-Migrations”启动迁移,然后再“Add-Migration Update1”添加迁移,这时候会生成 Update1 迁移文件,打开后进行如下更改:

namespace CodeFirstDemo.Migrations
{using System;using System.Data.Entity.Migrations;public partial class Update1 : DbMigration{public override void Up(){//AlterColumn("dbo.Products", "CreateTime", c => c.DateTime());AlterColumn("dbo.Products", "CreateTime", c => c.DateTime(defaultValueSql: "GETDATE()"));}public override void Down(){AlterColumn("dbo.Products", "CreateTime", c => c.DateTime());}}
}

代码什么意思,我就不多说了,改完之后,输入命令“Update-Database”更新到数据库,然后我们再进行测试:

可以看到数据是添加成功的,不放心的话可以去数据库瞧瞧,有人可能会有疑问,我们增加了 DateTime 值的默认 SQL,是不是就不需要对 DateTime 进行 DatabaseGenerated 配置了呢?这个我试过,去掉 DatabaseGenerated 是会报错的,至于为什么?其实你看到这,应该会明白上面 choon 所提出的两个问题,这边我说一下我的理解,但是不一定正确哦:

  1. 如果将 StoreGeneratedPattern 值设置为 Identity,只要一修改 CreateDate 字段就会抛异常:StoreGeneratedPattern 设置为 Identity,也就是标识键,但数据类型不是 int,而是 dateTime,最重要的是在增加或修改数据的时候,EF 找不到"the formula for the computed column"(计算列的公式-来自MSDN),所以不报错才怪。
  2. 如果把 StoreGeneratedPattern 值设置为 Computed 不会抛异常,但值仍然没有被修改,即使你写了 user.CreateDate = "xxx":将 StoreGeneratedPattern 设置为 Computed(执行插入和更新时都将生成一个值),既然是生成,你再进行 Set 也是没用的,而且像上面一样,找不到此列的计算公式(可以理解为 GETDATE),所以没用任何值添加或修改。

这是 EF CodeFirst 中的解决方式,至于“Model First”生成 edmx 中的方式解决,这个我还没试(肯定是修改 Config 配置文件),但我觉得都大同小异。还有就是,大家项目中使用 EF,如果可以的话,建议使用 CodeFirst 模式,不是一般的爽哦。。。

示例代码下载:http://pan.baidu.com/s/1pJG3jab

问题解决,要留下“痕迹”:

  • Adding CreatedDate to an entity using Entity Framework 5 Code First
  • Code First Data Annotations
  • Entity Framework “Code First + Computed GETDATE()”
  • Entity Framework 6 Code First default datetime value on insert
  • Entity Framework - “An error occurred while updating the entries. See the inner exception for details”
  • 记不得了...

转载于:https://www.cnblogs.com/xishuai/p/entity-framework-code-first-computed-getdate.html

关于有默认值的字段在用EF做插入操作时的思考(续)相关推荐

  1. Oracle删除带有默认值的字段

    1.平常,我们删除某个字段的方式为: ALTER TABLE 表名 DROP COLUMN 字段名; 但是,上面这种语句不能删除数据表中有主键约束和默认值的字段.即如果像下面这样建立的字段" ...

  2. hibernate 向数据库里设置了默认值的字段添加数据为null时失效的问题

    写ssh项目时设置了一个int类型的字段,想让他添加的时候默认为1 结果添加的时候不输入数据的话会将null转成0添加 最后再映射hbm文件里的property下设置insert="fals ...

  3. Oracle11g新特性:在线操作功能增强-表增加包含默认值的字段(转载)

    在11g以前,表中新增一个NOT NULL的字段是十分痛苦的事情,尤其是表很大的情况.不光是执行速度慢,而且由于现有数据长度的变化,很容易造成表中大量的行链接情况. 在11g中,这种情况得到了彻底的改 ...

  4. SQL删除带有默认值的字段

    语法:需要先删除对应的默认值,然后再删除列 1 . alter table tableName(表名) drop constraint '默认值约束名' 2 . alter table talbeNa ...

  5. 对比2个表mailbox_id字段的差集,然后做插入操作

    对比2个表mailbox_id字段的差集,并导出.然后利用循环insert插入. 1 2 3 4 5 6 7 8 9 kkmlmysqlpass=$(cat /usr/local/kk-ml/conf ...

  6. mysql给字段设置默认值,以及mysql的严格模式

    一.背景 在插入数据库时,报错#1364,后来才知道是字段在创建的时候,没有设置默认值的原因.关于默认值,我们都知道设置默认值为0或者null的时候,就算我们不插入该字段,数据库也会自动按照默认值填充 ...

  7. 数据库字段设置为非空默认值

    为什么数据库要设置默认值呢?因为我们希望在插入数据时,有意或无意间被忽略的字段能够交由MySQL按我们事先预想的方式处理,例如一些默认正常状态码.用户插入数据时候尚未设置的文本字段,诸如此类. 假设s ...

  8. mysql数据库字段默认值设为什么_为什么数据库字段需要设置默认值

    收到一只叮咚 mysql数据库默认对varchar的字段的值不就是空('')么,对数值默认是0,那还需要设置默认值的必要性何在?疑问的原因是没启用MySQL的严格模式(strictmode),很多快捷 ...

  9. mysql修改表中某个字段的默认值

    Mysql中用SQL增加.删除字段,修改字段名.字段类型.注释,调整字段顺序总结 在网站重构中,通常会进行数据结构的修改,所以添加,删除,增加mysql表的字段是难免的,有时为了方便,还会增加修改表或 ...

  10. 关于mysql设置varchar 字段的默认值''和null的区别,以及varchar和char的区别

    一.背景 根据业务需求,发现以前的同事在设计表的时候,很多字段都没有设置默认值.在mysql5.7版本之后,没有设定默认值的字段,在严格模式下是很容易报错的,所以我这边需要先给每个字段加上一个默认值. ...

最新文章

  1. Vue轻松入门,一起学起来!
  2. Java程序片:Java复制文件
  3. 第10步 (1)logback.xml日志配置(2) ftp(上传文件)服务器配置(3) idea注入和自动编译配置(4)项目提交gitee(5)fe助手和restlet client
  4. MySQL 使用Node.js异步查询结果为undefined的简单处理办法
  5. Word2010 给公式添加序号时公式变小解决方案
  6. 第七章:在Spark集群上使用文件中的数据加载成为graph并进行操作(3)
  7. stm08S单片机C语言编,STM8S单片机入门1(开发环境搭建)
  8. 6010dn 华为 组网 胖ap_1、认识胖瘦AP以及组网场景
  9. STL 算法/容器——总论
  10. 计算机通信技术的应用发展研究,计算机通信技术的发展与应用总结
  11. extern dllInport用法
  12. matlab作图有拉盖尔,拉盖尔高斯光束matlab
  13. [学习][记录] c++语言:从放弃到入门 <一> c++11新关键字以及引入的新特性
  14. AM信号的调制与解调
  15. 解决word中Mathtype按钮灰色问题(亲测有效)
  16. anconda各个版本下载
  17. NR 5G 5G-GUTI解读
  18. 【js组件】仿照steam样式制造自定义横向纵向滚动条
  19. Spring项目使用H2内存数据库做单元测试
  20. 2021.12.15.梦开始的地方.

热门文章

  1. mysql 使用gzip 压缩 文件,本地对 gzip 压缩的文件解压缩
  2. Ubuntu /CentOS 设置开机启动,添加自定义系统服务,自定义开机启动
  3. sql随机取一条数据
  4. 阶段3 3.SpringMVC·_02.参数绑定及自定义类型转换_3 配置解决中文乱码的过滤器
  5. 阿里百川SDK初始化失败 错误码是203
  6. Spring WebFlux 要革了谁的命?
  7. CMU Bomblab 答案
  8. JAVA 数组,(java核心技术 卷1)
  9. WPF 微信 MVVM 【续】发送部分QQ表情
  10. 工具-VS插件Resharper快捷键