现在的位置: 首页 > 综合 > 正文

linq更新部分数据时遇到的问题及解决办法

2013年06月05日 ⁄ 综合 ⁄ 共 3305字 ⁄ 字号 评论关闭

问题:因为每次更新的时候只是某个类的一部分,但是这个类的属性比较多.
更新函数如下

 

static void updateRe(log n)
        {
            using (DataClasses1DataContext dc = new DataClasses1DataContext())
            {
                using (StreamWriter sw=new StreamWriter("t.log"))
                {
                    dc.Log = sw;
                    dc.log.Attach(n);
                    dc.Refresh(RefreshMode.KeepCurrentValues,n);

                    dc.SubmitChanges();
                }
            }
        }

 

            updateRe(n1);
        }

static void Main(string[] args)
        {
            log n1 
= new log() ;
            n1.logId 
= 1;
            n1.logMessage 
= "xxxx";

 

 

这时候产生的sql如下
SELECT [t0].[logId], [t0].[logMessage], [t0].[x]
FROM [dbo].[log] AS [t0]
WHERE [t0].[logId] = @p0
-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [1]

UPDATE [dbo].[log]
SET [logMessage] = @p1, [x] = @p2
WHERE [logId] = @p0
-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [1]
-- @p1: Input VarChar (Size = 4; Prec = 0; Scale = 0) [xxxx]
-- @p2: Input NChar (Size = 10; Prec = 0; Scale = 0) [Null]

 

问题就是这样做会将你没有符过值的都更新为Null,我继续做实验,将main函数改为如下

 

 

 

static void Main(string[] args)
        {
            DataClasses1DataContext dc 
= new DataClasses1DataContext();
            log n1 
= (from x in dc.log
                      select x).SingleOrDefault(c 
=> c.logId == 1);
            n1.logMessage 
= "xxxy";

            updateRe(n1);
        }

 

会引发"已尝试 Attach 或 Add 实体,该实体不是新实体,可能是从其他 DataContext 中加载来的。不支持这种操作。"异常,没找到把n1从它的DataContext脱离的办法.所以我使用如下的解决方案:
在log的部分类中书写克隆方法:

 

public partial class log
    {
        
public log Clone()
        {
            log l 
= new log();
            l.logId 
= this.logId;
            l.logMessage 
= this.logMessage;
            l.x 
= this.x;
            
return l;
        }
   }
static void Main(string[] args)
        {
            DataClasses1DataContext dc 
= new DataClasses1DataContext();
            log n1 
= ((from x in dc.log
                      select x).SingleOrDefault(c 
=> c.logId == 1)).Clone();
            n1.logMessage 
= "xxxy";

            updateRe(n1);
}

 

 

生成的sql语句如下
SELECT [t0].[logId], [t0].[logMessage], [t0].[x]
FROM [dbo].[log] AS [t0]
WHERE [t0].[logId] = @p0
-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [1]

UPDATE [dbo].[log]
SET [logMessage] = @p1
WHERE [logId] = @p0
-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [1]
-- @p1: Input VarChar (Size = 4; Prec = 0; Scale = 0) [xxxy]

感觉这个Clone()方法也不是好的解决方案,大家有什么好的想法么?

 ps:

可以使用反射代码自动拷贝dbml中的相应属性

Code
class Utility
    {
        
public static T Clone<T>(T source) where T: new() 
        {
            T t 
= new T();
            var ps 
= source.GetType().GetProperties().Where(p => p.GetCustomAttributes(false)
               .Where(a 
=> a is System.Data.Linq.Mapping.ColumnAttribute).Count() != 0);
            
foreach (var item in ps)
            {
                t.GetType().GetProperty(item.Name).SetValue(t, item.GetValue(source, 
null), null);
            }
            
return t;
        }
    }

 

网友:@Gray Zhang 的这个方法我觉得不错,整理如下:

 

static void Update(int id, Action<log> updater)
        {
            
using (DataClasses1DataContext ctx = new DataClasses1DataContext())
            {
                
ctx.Log = Console.Out;
                log entity 
= ctx.log.First(c => c.logId == id);
                
//执行updater
                updater(entity);
                ctx.SubmitChanges();
            }
        }
        
public static void set(log l)
        {
            l.logMessage 
= "xxtx";
        }
        
static void Main(string[] args)
        {
            Update(
1set);
        }

 

 

抱歉!评论已关闭.