请教一个关于SQL语句更新的写法的问题

niuhejun 2015-06-03 09:53:11
遇到一个更新需求:

1.表里有四个字段。
2.更新的时候不确定要更新哪几个字段。有可能是全部,也有可能是某几个。

我想的解决方案:
1.定义一个实体类。里面是四个对应的数据库字段的属性。
2.SQL语句是拼接的,在拼接的时候逐个判断属性值是否为空,如果为空就不拼接对应字段。


遇到的问题以及疑问:
1.在拼接的时候Update语句主要拼接 Set之后和WHERE之前的部分,每一句都要带一个逗号,由于在拼接的时候不知道那个字段为空,所以只能是在拼接后的语句去处理这个逗号(拼接完后WHERE前多了一个逗号)
2.关于属性,int型的变量及其属性应该默认值就是0 ,那我应该怎么处理,赋值为0和不赋值(就是不更改当前字段)这个情况呢
3.关于属性,Datetime类型。默认值问题。如何判断datetime类型的变量对应的属性没赋值呢?

求指点,谢谢
...全文
404 点赞 收藏 25
写回复
25 条回复
hlm750908 2015年06月05日
整体更新前需要获取一次旧值,我想楼主的意思是不想获取旧值,就可以更新,所以不关注的字段不要牵涉进来,18楼的答复符合你的需求
回复 点赞
leeya66 2015年06月05日
全部字段都更新啊,这个是最合理的
回复 点赞
我叫小菜菜 2015年06月05日
引用 23 楼 hlm750908 的回复:
整体更新前需要获取一次旧值,我想楼主的意思是不想获取旧值,就可以更新,所以不关注的字段不要牵涉进来,18楼的答复符合你的需求
不获取一次旧值,那么就有可能会出现update语句失败:因为无法指定where子句。 比如 {id:123,name:CC,sex:m} 如果不获取旧值,初始化将是{id:?,name:?sex:?},假设设置id=34,name=BB,请问这“id=34”依据是啥,为什么一定要是34,而不能是35,36?随意的话,那应该是insert,而不是update了~~ 上面所说的以对象为基本单位,就是这个原因。 当然,动态拼接sql语句的办法,可以应用于任何场合,而且拼接字符串本身不是难题,无论多么复杂的字符串都是肯定能拼接出来的。
回复 点赞
一枚大帅哥 2015年06月04日
引用 2 楼 skyandcode 的回复:
一般这种情况是全部字段都更新,你这里只有4个字段,如果有10个、20个字段呢? update只更新一条记录的多个字段不会有太大影响。 1.是要自己处理逗号 2.3. 对于值类型,你可以用可空类型,默认就是空
这个正解
回复 点赞
qbilbo 2015年06月04日
全部更新是指把你类中所有的属性都更新,而不是数据库表中的字段全更新。 把属性的数据类型设置成int?,datetime?是为了可以和数据库表中字段类型完全匹配。从而不用担心int不能为null之类的问题。也许你的问题2中更新字段个数不一致就是这个原因。 如果你更新字段个数不一致是由于业务逻辑引起的,比如在有些特定情况下不更新,那建议改进一下你的这个类。比如:用于更新的属性为只读与赋值属性分开,在赋值属性的set方法里,根据业务逻辑来设定如何更新用于写入数据库的属性。
回复 点赞
wish907 2015年06月04日
你难道就不能在拼的时候在加','之前先if(是否有值)不就好了,至于int 和datetime的时间,设一个不应该出现的值不就好了
回复 点赞
我叫小菜菜 2015年06月04日
引用 17 楼 xuzuning 的回复:
从数据库操作角度看,你的逻辑是行不通的 因为 update 是修改记录中原有的值,既然是发生了修改,那么改一个字段和改两个字段还是全改,开销是一样的。而全改时效率反而更高。 另外,如果带有 NOT NULL 属性的字段,insert 和 update 时如果不赋值,是通不过语法检查的 再说,判断属性值是否为空,如果为空就不拼接对应字段也是欠妥的,如果我就是想将原来的值删去呢?你这样不就删不掉了吗 当然你想拼装 update 也是可以的,但是表是固定了的,update 是活的有什么意义呢?徒劳的消耗资源 拼装 SQL 指令串,多在动态查询时使用。 构建时可将各子句 Add 到 List<string> 循环结束后再用 string.Join 连接成字符串。根本就不会出现多余的逗号问题 即便你不想改变你的思路和先用代码,也只需在拼装后用 SubString 截取一下
斑竹正解。 数据库的CURD操作以实体为最小单位,而对象也是面向对象编程的核心概念,这已经是面向对象编程的共识(我不知道是不是规范)。【压根就不确定要更新那个或者那几个字段呢】,你为什么要关心到底更新了哪些字段呢?你应该把思路从【应该更新哪些字段】上升到【应该更新哪个对象】。正是因为一个对象可能有几十个属性,所以才把它封装为一个对象,从而屏蔽属性细节,把更多的精力放在业务逻辑上,而不是耗费在这些字段中。 至于效率问题: 对象属性都是固定的,而时间主要耗费在资源初始化、网络延迟和数据传输。 资源初始化方面比如打开数据库、索引定位数据记录,这些都是相同的; 网络延迟是系统因素; 数据传输方面都是整个对象为参数,那么对象的所有属性都会初始化为默认值,多出来的只是某些字段的赋值操作,而赋值操作的时间复杂度通常都是O(1),所以算下来效率并不会影响很大,但是对于业务逻辑的处理影响之大简直无可估量。 关于空值问题和默认值问题的处理: 从数据库逆向工程生成实体定义,如果数据库中int/double数字类型允许为空,那么生成的实体类会把这些类型映射成可空类型(int、bool等这些类型不能表示数据库中的“Null” 。因此C#提供了“可空类型”这种语法,只要在类型后加?就构成了可空的数据类型,比如int?、bool?,这样int? i=null 就可以了。),其实就是实现了System.Nullable<T>接口的int和bool,当然double和其他类型都有相应的可空类型~
回复 点赞
niuhejun 2015年06月04日
引用 1 楼 zhi_ai_yaya 的回复:
用存储过程吧。
大哥,能详细解释下吗?存储过程不也得把要修改的所有参数传入吗?如果我只是想修改里面的一个两个,参数应该怎么赋值呢
回复 点赞
niuhejun 2015年06月04日
引用 3 楼 bbjiabcd 的回复:
把查询出来一条记录的所有字段修改后全部放进实体类中,更新的时候全部更新就好了。
如果一个记录有20个字段,难道为了更新里面的三四个字段,就要获取全部的数据付给实体类,在进行更新吗?我个人以为,为了更新四五个字段而更新全部的几十个字段,是不是得不偿失啊
回复 点赞
niuhejun 2015年06月04日
引用 3 楼 bbjiabcd 的回复:
把查询出来一条记录的所有字段修改后全部放进实体类中,更新的时候全部更新就好了。
如果一个记录有20个字段,难道为了更新里面的三四个字段,就要获取全部的数据付给实体类,在进行更新吗?我个人以为,为了更新四五个字段而更新全部的几十个字段,是不是得不偿失啊
回复 点赞
EdsionWang 2015年06月04日
int和DateTime你都可以给一些特殊值做初始值。比如int可以设一个负数,或者int.MaxValue(考虑你系统内不会出现的值)
回复 点赞
qbilbo 2015年06月04日
属性的类型改为:int?,datetime?就可以为null了。 这样所有字段一起更新应该也没问题了吧。
回复 点赞
bbjiabcd 2015年06月04日
把查询出来一条记录的所有字段修改后全部放进实体类中,更新的时候全部更新就好了。
回复 点赞
skyandcode 2015年06月04日
一般这种情况是全部字段都更新,你这里只有4个字段,如果有10个、20个字段呢? update只更新一条记录的多个字段不会有太大影响。 1.是要自己处理逗号 2.3. 对于值类型,你可以用可空类型,默认就是空
回复 点赞
我叫小菜菜 2015年06月04日
用存储过程吧。
回复 点赞
gossipchat 2015年06月04日
int,datetime建议定义为int?,datetime?可空类型,默认赋值为null
回复 点赞
0802023028 2015年06月04日
你都定义好了实体类,还不好拼SQL啊,直接写就OK,当然也可以写个扩展方法动态组装SQL
回复 点赞
bbjiabcd 2015年06月04日
引用 6 楼 niuhejun 的回复:
[quote=引用 3 楼 bbjiabcd 的回复:] 把查询出来一条记录的所有字段修改后全部放进实体类中,更新的时候全部更新就好了。
如果一个记录有20个字段,难道为了更新里面的三四个字段,就要获取全部的数据付给实体类,在进行更新吗?我个人以为,为了更新四五个字段而更新全部的几十个字段,是不是得不偿失啊[/quote] Java中Hibernate的原理就是我说的这样。我倒觉得你一个一个字段判断再拼接SQL更加得不偿失
回复 点赞
smthgdin_020 2015年06月04日
1.可以拼后再去掉逗号;也可以在已知更新字段的前提下,去控制最后一个字段的字符串。 2,3个问题,可以给你个思路,就是在实体里定义一个hashtable去保存哪些字段做了更新。 比如: private readonly Hashtable ChangeFlag = new Hashtable(); private string address; public virtual string Address { get { return address; } set { address= value; this.ChangeFlag ["Address"] = true; } } 这样,每当你给属性赋值,hashtable都会添加哪个属性已经变化需要update。 对于new出来的实体,判断是否给主键赋值,或者在构造函数里先清空以下hashtable就可以解决你得问题。
回复 点赞
xuzuning 2015年06月04日
从数据库操作角度看,你的逻辑是行不通的 因为 update 是修改记录中原有的值,既然是发生了修改,那么改一个字段和改两个字段还是全改,开销是一样的。而全改时效率反而更高。 另外,如果带有 NOT NULL 属性的字段,insert 和 update 时如果不赋值,是通不过语法检查的 再说,判断属性值是否为空,如果为空就不拼接对应字段也是欠妥的,如果我就是想将原来的值删去呢?你这样不就删不掉了吗 当然你想拼装 update 也是可以的,但是表是固定了的,update 是活的有什么意义呢?徒劳的消耗资源 拼装 SQL 指令串,多在动态查询时使用。 构建时可将各子句 Add 到 List<string> 循环结束后再用 string.Join 连接成字符串。根本就不会出现多余的逗号问题 即便你不想改变你的思路和先用代码,也只需在拼装后用 SubString 截取一下
回复 点赞
发动态
发帖子
C#
创建于2007-09-28

8.4w+

社区成员

64.0w+

社区内容

.NET技术 C#
社区公告
暂无公告