linq, nightmaire
搞死我。
只要涉及到数据更新
就搞不清怎么回事。
折腾死我了
体会一:用linq to sql,必须同时用sqlprofiler
附:for sqlexpress的sql profile: SQL PROFILE
体会二:如果一个数据可能发生变化,及时用refresh更新数据。这里要注意,不要把table直接做为Refresh的参数。尽可能的缩小更新的范围。
比如这段代码:
DBHelper.Instance.db.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, DBHelper.Instance.db.tb_users);
后台执行的sql:
FROM [dbo].[tb_user] AS [t0]
exec sp_executesql N'SELECT [t0].[id], [t0].[account], [t0].[password], [t0].[name], [t0].[phone], [t0].[email], [t0].[last_login_time], [t0].[dept_id], [t0].[status], [t0].[attribute1], [t0].[attribute2], [t0].[attribute3], [t0].[attribute4], [t0].[attribute5]
FROM [dbo].[tb_user] AS [t0]
WHERE [t0].[id] = @p0',N'@p0 int',@p0=1227
exec sp_executesql N'SELECT [t0].[id], [t0].[account], [t0].[password], [t0].[name], [t0].[phone], [t0].[email], [t0].[last_login_time], [t0].[dept_id], [t0].[status], [t0].[attribute1], [t0].[attribute2], [t0].[attribute3], [t0].[attribute4], [t0].[attribute5]
FROM [dbo].[tb_user] AS [t0]
WHERE [t0].[id] = @p0',N'@p0 int',@p0=1228
首先会把所有的tb_user表数据检索一次。
再把tb_user表中的 每 一条记录再检索一次。 可想而知,这有多浪费资源。 所以,在想更新linq内存 中的对象值的时候,务必要具体到一条记录或几条记录,千万别省事来个<table>
体会三:必须熟练三种refreshmode的区别。
看这段代码:
1: string account = Request.QueryString["user"];
运行到第2句时,没有sql产生。
2: var user = from t in DBHelper.Instance.db.tb_users
where t.account == account
select t;
3: DBHelper.Instance.db.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, user);
这时偷偷去数据库把这个用户的name改一下
在visual的立即窗口运行user.first().name,会产生具体的select语句。
再运行第3句。我们把refreshmode改一下,下面说下运行结果:
- OverwriteCurrentValues: 这个最容易理解。内存中的这个user值被数据库的值更新了
- KeepChanges: 这个不错,内存中的值也被更新了。不同的是,如果之前我们用user.name="xxx",改变了user的内容,这个name列就不会被数据库值冲掉。看来这个选项很适合于乐观并发情况的处理。
- KeepCurrentValues: 这个要观察效果,还得再做些手脚。
我们在第3行前增加代码:
2.5: user.First().name = "赵五";
在第3行后增加代码:
4: DBHelper.Instance.db.SubmitChanges();
下面我们来做手脚。
假设user.first().name的值是张三 运行完第2句,我们在立即窗口用user.first()看看读取来的值。(也就是让linq读下数据库的值)
嗯,是张三,没错。
然后我们 改下数据库的值,改成李四
运行完第3句,在立即窗口用user.first()看看内存的值。是赵五。
没看到来啥变化啊。数据库的值对内存的对象没影响。
别急,让我们运行下面两行代码。
如果我们没运行refresh,很明显,程序会报那个最著名的错误:找不到数据行。 但现在我们refresh过了,就不一样了。 运行4. 没有提示错误。再看数据库中的值,变成赵五了,而且sql profile显示,update语句中的where,就是name=李四,而非name=张三
哈,真象大白,原来keepcurrentvalues是用数据库中的值来冲掉内存对象的ori value用的。
不对,这么说,如果用keepsurrentvalues,那么在我们submitchanges的时候,即使我们没有改 过name字段的值,也就是把2.5去掉,在submitchanges的时候,linq还是会把name字段写回 去,也就是写成linq当初从数据库中读的那个值:张三。试验了一把,果然如此。
总算明白机理了。但是,啥前用keepcurrentvalues呢?嗯,希望最后一次用户保存的信息有效 时,应该用keepcurrentvalues。如果只希望保存最后一次“更新过”的数据,就用keepchanges。应该说,乐观并发,采用keepcurrentvalues更合适。
总结:使用linq,彻底验证了那句名言,具体怎么说的忘了。大概意思是说:相信你所不了解的东西,你的梦魇从此就开始了。
所以,要想用linq,想省事,老老实实用sql profile看看linq如何动作吧。否则只是无穷无尽的麻烦。
浙公网安备 33010602011771号