首页 新闻 会员 周边

ef 数据更新的疑惑

0
悬赏园豆:100 [已解决问题] 解决于 2014-06-16 16:24

大多数系统的表单是比较简单的,表内的字段在表单上全部体现出来了,提交数据的时候可以将表单转换为数据实体直接用 SaveChanges 保存。

目前我遇到的问题是表单内只有表内的部分字段,SaveChanges的话EF会把表单内没有的字段设为null更新了,因为实体中的属性值是null

我知道可以标记字段为已更新 db.Entry(query).Property(x => x.id).IsModified;

但这种方式实际上也存在缺陷,标记字段的前提是字段值不为空,如果表单上字段的数据需要清空这样就不会被标记为已更新了

不能使用mvc自带的 TryUpdateModel 方法,controller 接收的post并不是数据实体,中间需要用 AutoMapper 转换的

Y2zz的主页 Y2zz | 菜鸟二级 | 园豆:393
提问于:2014-06-14 10:39
< >
分享
最佳答案
0

假设你有 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();

 

 

收获园豆:80
Launcher | 高人七级 |园豆:45045 | 2014-06-16 11:44

 试了一把,失败 没有产生update

Y2zz | 园豆:393 (菜鸟二级) | 2014-06-16 15:29

@Y2zz: 不明白你的失败是什么意思

Launcher | 园豆:45045 (高人七级) | 2014-06-16 15:35

@Launcher: 

var data = db.xxx.Single(x => x.id == model.Id);

var cost = Mapper.Map(model, data);

db.SaveChanges();

 

用SQL Server Profiler监听 没又看到update语句

Y2zz | 园豆:393 (菜鸟二级) | 2014-06-16 15:37

@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 | 园豆:45045 (高人七级) | 2014-06-16 15:42

@Launcher: 知道问题出在哪儿了。。。。。 我没有更改内容,所以不会产生update

Y2zz | 园豆:393 (菜鸟二级) | 2014-06-16 16:24
其他回答(3)
0

没有无缺陷的设计,这是一个基本的原理。

还原一下你的环境,大概应该是这样的

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()

当然这样的写法的问题是,你会认为重复取了数据,是无用功,浪费资源来着?

收获园豆:10
爱编程的大叔 | 园豆:30839 (高人七级) | 2014-06-14 11:50

感谢你抽空回复我的问题:)

 

1. 字段太多,不可能手写,不然回到最原始的方式了

2. 针对场景有model,主要就是场景数据更新就会把其他字段覆盖

3. 回到问题1了,字段需要手工赋值,实际上我会 new entity(),然后 Attach 再SaveChanges()

 

支持(0) 反对(0) Y2zz | 园豆:393 (菜鸟二级) | 2014-06-14 12:03

@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进行保存操作。

支持(0) 反对(0) 爱编程的大叔 | 园豆:30839 (高人七级) | 2014-06-14 12:12
0

这种情况躲不过逐个赋值,

1 把表单中未用到的字段存在隐藏域中,提交时再给实体, 这样比保存时先从DB取到实体再做变更 代价可能更小一点

2 提交时 再加载一次实体将表单中变更的字段赋值后再次保存 这样数据库连接同样还是只打开关闭一次。

 

Zery | 园豆:6151 (大侠五级) | 2014-06-15 12:02
0

建议你看看领域驱动设计之类的文章,对Model、Dto、Domain概念做个了解,相信能帮助你解开疑惑。

收获园豆:10
玻璃鱼儿 | 园豆:214 (菜鸟二级) | 2014-06-15 14:51
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册