关于有默认值的字段在用EF做插入操作时的思考

原文:关于有默认值的字段在用EF做插入操作时的思考

今天在用EF做插入操作的时候发现数据库中一个datetime类型的字段(CreateDate)的值居然全部为null。于是赶紧看表结构发现CreateDate字段居然是允许为空的。

虽然为空,但是设置了默认值getdate(),按说不应该为null的。于是开始测试。

字段允许Null值的情况

Users表结构如下:

假如一个字段有了默认值,并且又允许为Null,在做插入操作时会发生什么?

如上图中的表结构,CreateDate是允许为null的,而又有默认值getdate()。这样在用传统SQL语句和EF做插入操作时分别会发生什么呢?

先看传统SQL语句:

insert into Users(Username,Password) values('test','123456')

插入结果:

使用SQL完全没有问题。

再看使用EF:

Users user = new Users();
user.Username = "test2";
user.Password = "123456";

TestEntities entity = new TestEntities();
entity.Users.Add(user);
int result = entity.SaveChanges();

插入结果:

使用EF插入居然为NULL!!!于是立刻打开SQL Server Profiler监测生成的SQL,EF居然生成了下面的SQL:

没赋值的字段,EF生成SQL的时候居然都置为NULL,管你有没有设默认值!

可能是EF比较娇情,我字段允许为NULL,EF生成SQL时就置为null了。那我把字段设为不允许为NULL,EF又会生成怎样的SQL呢?

字段不允许Null值的情况

Users表结构如下:

这一次CreateDate不允许为NULL了,使用SQL理所当然地一切正常:

insert into Users(Username,Password) values('admin','123456')

那再看下用EF:

Users user = new Users();
user.Username = "admin";
user.Password = "123456";

TestEntities entity = new TestEntities();
entity.Users.Add(user);
int result = entity.SaveChanges();

结果。。。

”从 datetime2 数据类型到 datetime 数据类型的转换产生一个超出范围的值。“

EF很傲娇地抛了个异常!!为什么会抛出这个异常?这个异常神马意思?于是照妖镜SQL Server Profiler又出场了:

日期类型的字段如果不赋值会给默认值“0001-01-01 00:00:00”,这和生成SQL无关,是在生成SQL之前CLR进行的初始化操作,同理String类型的字段如果不赋值会给默认值String.Empty!

但是,那也不至于抛异常啊,顶多字段值存储为“0001-01-01 00:00:00”呗。

于是查MSDN发现datetime类型的日期范围仅支持1750-01-01 00:00:00至9999-12-31 23:59:59.997,而0001-01-01 00:00:00不在此范围内,所以抛出异常。原来如此。

datetime和datetime2支持的日期范围如下:

结论

如此看来无论字段有没有默认值,使用EF插入时都没有任何实际作用了。因此如果你使用EF建议干脆直接写死算了。比如user.CreateDate = DateTime.Now。

ps.这里只是举个例子,事实上,在实际项目中不建议写成DateTime.Now,因为数据库系统时间和服务器时间一般是不同的,笔者实际项目中其实是封装了一个方法叫GetSQLServerSystemDateTime。

除此之外是否还有别的方法呢?

方法是有的,打开EF的.edmx文件,找到<EntityType Name="表名">节点,把如下节点:

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

改成:

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

即可。

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

笔者经过实际测试发现:

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

所以如果你使用EF,我还是建议采用第一种方式,直接在程序中赋值user.CreateDate = xx.GetSQLServerSystemDateTime()。这种方法省事且安全。修改edmx文件太麻烦,况且每增加一个datetime类型的字段都要修改一次edmx文件。

最后感谢大家提出的建议,欢迎大家亲自测试并把结果反馈给我。

时间: 2024-09-14 08:11:51

关于有默认值的字段在用EF做插入操作时的思考的相关文章

oracle表,字段名有“/”在做hibernate映射时怎么做?

问题描述 oracle表,字段名有"/"在做hibernate映射时怎么做?<propertyname="bev2edUser"type="java.lang.String"><columnname="/BEV2/ED_USER"length="12"></column></property>这样会报错ORA-00904::标识符无效咋办啊? 解决方案 解决方

大神们,oracle表,字段名有“/”在做hibernate映射时怎么做?

问题描述 oracle表,字段名有"/"在做hibernate映射时怎么做?<propertyname="bev2edUser"type="java.lang.String"><columnname="/BEV2/ED_USER"length="12"></column></property>这样会报错ORA-00904::标识符无效咋办啊? 解决方案 解决方

JPA设置默认值,字段长度

@Column(nullable = false, columnDefinition = "varchar(20) default 'LTD'") @Column(columnDefinition = "varchar(20) default 'LTD' not null")

MySQL修改字段默认值

环境 MySQL 5.1 + 命令行工具 问题 MySQL修改字段默认值 解决 alter table topic alter column cateId set default '2'; 语法总结 alter table表名alter column字段名drop default; (若本身存在默认值,则先删除) alter table表名 alter column 字段名 set default默认值;(若本身不存在则可以直接设定) 查看本栏目更多精彩内容:http://www.biancen

修改SQL Server数据库相关字段的默认值

  原来的数据库有好多类型的数据默认值都是 null 值,为以后在实际开发过程中带了好多不变.这个null其实也有好处,我想可以节省数据库的空间,在新增数据的时候还可以提高速度.不过还是应领导要求写了下面的代码.在CSDN的大侠帮助下完成的. declare @t table(id int identity(1,1),tbname varchar(256), colname varchar(256),xtype varchar(20)) insert into @t select a.name,

sql2008日期字段默认值设置为当前日期

 在进行机房收费系统时,数据库中有个StudentOnline表(学生上机). 在学生上机成功后,需要向StudentOnline表写入数据.其中上机日期的写入有两种方式:一种是在界面获得当前日期,然后将其作为参数插入数据表中:另一种解决方案是在表中设置日期字段默认值为当前日期,这样我们就不需要向数据表传入日期这个参数,因为数据表会自动填充. 下面我们用一个小Demo给大家演示如何设置日期字段默认值为当前日期. 首先我们创建一个表名为Demo的数据表,并设置StartDate字段默认值为当前日期

随机数字-access 中 字段“点击量”,设置默认值:int(100*rnd())+100 点击量不变化?

问题描述 access 中 字段"点击量",设置默认值:int(100*rnd())+100 点击量不变化? access 中 字段"点击量",设置默认值:int(100*rnd())+100 为什么发布新闻之后,点击量不变化?想要效果,点击量是一个100到200之间的随机数字,但,第一篇随机的,后面再发就和第一篇的点击量相同了. 解决方案 先调用Randomize否则每次产生的是一样的 解决方案二: 先调用Randomize否则每次产生的是一样的

阿里云HybridDB for PG实践 - 列存储加字段和默认值

标签 PostgreSQL , Greenplum , 相对偏移 , 列存储 , appendonly , AO表 背景 Greenplum的Append only table支持更新.删除.通过什么支持呢?bitmap文件,标记被删除的行. 因此在更新,删除后,数据可能膨胀. 另一方面,列存储每列一个文件,同一行通过偏移对应起来.例如INT8的两个字段,通过偏移很快能找到某一行的A列对应的B列. 接下来谈谈加字段,在加字段时,AO表示不会REWRITE TABLE的.如果AO表以及有一些垃圾(

sql字段默认值设置成存储过程

问题描述 sql字段默认值设置成存储过程 存储过程 [dbo].[autoidu] N'客户编号'执行后能得到一个字符串,比如是'123456789',但每次值是不一样的. 现在有个表 客户资料,我想加个字段 客户编号,我希望设置默认值为上面的存储过程执行后的值.应该怎么设置? alter table 客户资料 add 客户编号 nvarchar(15) default [dbo].[autoidu] N'客户编号' 是不是不能这样?有没有什么办法解决? 解决方案 alter table 客户资