大多数系统的表单是比较简单的,表内的字段在表单上全部体现出来了,提交数据的时候可以将表单转换为数据实体直接用 SaveChanges 保存。
目前我遇到的问题是表单内只有表内的部分字段,SaveChanges的话EF会把表单内没有的字段设为null更新了,因为实体中的属性值是null
我知道可以标记字段为已更新 db.Entry(query).Property(x => x.id).IsModified;
但这种方式实际上也存在缺陷,标记字段的前提是字段值不为空,如果表单上字段的数据需要清空这样就不会被标记为已更新了
不能使用mvc自带的 TryUpdateModel 方法,controller 接收的post并不是数据实体,中间需要用 AutoMapper 转换的
假设你有 Model {A,B,C,D,E,F},ViewModel{A,B,C},其中 A 为主键,那么更新时的伪代码为:
var model = dbContext.ModelSet.Single(o=> o.A = viewModel.A);
AutoMapper.Map(viewModel,model); // 因为 ViewModel 只有 A,B,C 三个属性,因此只会将 B,C 的值更新到 Model
dbContext.SaveChanges();
试了一把,失败 没有产生update
@Y2zz: 不明白你的失败是什么意思
@Launcher:
var data = db.xxx.Single(x => x.id == model.Id);
var cost = Mapper.Map(model, data);
db.SaveChanges();
用SQL Server Profiler监听 没又看到update语句
@Y2zz: SaveChanges 没有抛异常吗? Map 后 data 的属性被更改了吗?要知道,这可是我一直在使用的最基本的更新语句。类似于如下的语句:
var data = db.xxx.Single(x => x.id == model.Id);
data.B = sdfdsf; // 等同于 Mapper.Map
data.C = dfdf; // 等同于 Mapper.Map
db.SaveChanges();
现在你告诉上面的语句失败了,然后又没有异常,怎么可能呢?要知道上面的更新代码可是最基本的使用方式。如果这都不能成功,那么你以前的代码是怎么运行起来的呢?
@Launcher: 知道问题出在哪儿了。。。。。 我没有更改内容,所以不会产生update
没有无缺陷的设计,这是一个基本的原理。
还原一下你的环境,大概应该是这样的
MyTable , Fields: A/B/C/D/E/F/G
现在在你的表单上只有A/B/C三个字段。
而且你只想更新这三个字段,另外三个字段保持原值。
现在问题来了:
1、如何判断只有三个字段,开发员手写?还是根据Model的属性遍历。
2、如果是遍历的话,确实会找到所有的字段,除非你再为这个场景专门写一个MODEL。
3、如果你知道是哪一些字段要更新,下面的代码不会更新到无关的字段的
var query= from c in myDataContext.Table
where c.primaryid.equals(myPrimaryID)
query.A=model.A
query.B=model.B
query.C=model.C
MyDataContext.SaveChanges()
当然这样的写法的问题是,你会认为重复取了数据,是无用功,浪费资源来着?
感谢你抽空回复我的问题:)
1. 字段太多,不可能手写,不然回到最原始的方式了
2. 针对场景有model,主要就是场景数据更新就会把其他字段覆盖
3. 回到问题1了,字段需要手工赋值,实际上我会 new entity(),然后 Attach 再SaveChanges()
@Y2zz:
如果有MODEL,MODEL中只有A、B、C三个字段,应该好解决。
不需要手写,通过遍历MODEL的属性,将A、B、C字段的新值写到查询出来的query row里面,这样MODEL中没有的属性不会被更改。
For each property in Model
query.property.value=Model.Property.value
next for
然后对query进行保存操作。
这种情况躲不过逐个赋值,
1 把表单中未用到的字段存在隐藏域中,提交时再给实体, 这样比保存时先从DB取到实体再做变更 代价可能更小一点
2 提交时 再加载一次实体将表单中变更的字段赋值后再次保存 这样数据库连接同样还是只打开关闭一次。
建议你看看领域驱动设计之类的文章,对Model、Dto、Domain概念做个了解,相信能帮助你解开疑惑。