近来用到了Linq2Sql的方法,遇到了一个更新问题。在此记录下来与大家分享。
废话不多说,请看:
1.数据库表结构如下:
需求很简单,一个Order表保存订单,一个OrderDetails保存订单明细。同时2个表有主外键的关系。
数据库里数据如下:
好的,是不是很简单。现在如果我们要把Order_Details表的EntryId等于3的那条记录的Qty更新成200,该怎么做呢?
Linq2Sql实现起来十分简单,代码如下:
View Code
1 static void Main(string[] args) 2 { 3 var item = default(Order_Detail); 4 using (var db = new ToyDataContext()) 5 { 6 item = db.GetTable<Order_Detail>().FirstOrDefault(p => p.EntryId == 3); 7 } 8 9 if (item != null) 10 { 11 item.Qry=100; 12 using (var db=new ToyDataContext()) 13 { 14 db.GetTable<Order_Detail>().Attach(item); 15 db.Refresh(System.Data.Linq.RefreshMode.KeepCurrentValues, item); 16 db.SubmitChanges(); 17 } 18 } 19 }
当当当,但是在执行的时候,却抛出如下异常
原来是这个实体对应的表有若干个关联表,在生成实体类时会自动产生:EntityRef<Order> Order这样的属性,但是Linq2Sql默认是延迟加载的,所以在Attach的时候,这些EntityRef还没有加载。
好了,于是我们想到了可以在首次从数据库查询的时候不启用延迟加载,将DeferredLoadingEnabled设置为false。这样,在执行查询时,将不会为实体加载任何需延迟查询的数据。
代码如下:
View Code
1 static void Main(string[] args) 2 { 3 var item = default(Order_Detail); 4 using (var db = new ToyDataContext()) 5 { 6 db.DeferredLoadingEnabled = false;//不会为实体加载任何需延迟查询的数据 7 item = db.GetTable<Order_Detail>().FirstOrDefault(p => p.EntryId == 3); 8 } 9 10 if (item != null) 11 { 12 item.Qry = 200; 13 using (var db = new ToyDataContext()) 14 { 15 db.GetTable<Order_Detail>().Attach(item); 16 db.Refresh(System.Data.Linq.RefreshMode.KeepCurrentValues, item); 17 db.SubmitChanges(); 18 } 19 } 20 }
另外还可以通过手动Detach方法,手工移除关联
代码如下:
View Code
1 static void Main(string[] args) 2 { 3 var item = default(Order_Detail); 4 using (var db = new ToyDataContext()) 5 { 6 // db.DeferredLoadingEnabled = false;//不会为实体加载任何需延迟查询的数据 7 item = db.GetTable<Order_Detail>().FirstOrDefault(p => p.EntryId == 3); 8 } 9 10 if (item != null) 11 { 12 item.Qry = 200; 13 using (var db = new ToyDataContext()) 14 { 15 Detatch(item);//Detatch 16 db.GetTable<Order_Detail>().Attach(item); 17 db.Refresh(System.Data.Linq.RefreshMode.KeepCurrentValues, item); 18 db.SubmitChanges(); 19 } 20 } 21 } 22 23 public static void Detatch<TEntity>(TEntity entity) 24 { 25 Type t = entity.GetType(); 26 System.Reflection.PropertyInfo[] properties = t.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); 27 foreach (var property in properties) 28 { 29 string name = property.Name; 30 if (property.PropertyType.IsGenericType && 31 property.PropertyType.GetGenericTypeDefinition() == typeof(EntitySet<>)) 32 { 33 property.SetValue(entity, null, null); 34 } 35 } 36 System.Reflection.FieldInfo[] fields = t.GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); 37 foreach (var field in fields) 38 { 39 string name = field.Name; 40 if (field.FieldType.IsGenericType && 41 field.FieldType.GetGenericTypeDefinition() == typeof(EntityRef<>)) 42 { 43 field.SetValue(entity, null); 44 } 45 } 46 System.Reflection.EventInfo eventPropertyChanged = t.GetEvent("PropertyChanged"); 47 System.Reflection.EventInfo eventPropertyChanging = t.GetEvent("PropertyChanging"); 48 if (eventPropertyChanged != null) 49 { 50 eventPropertyChanged.RemoveEventHandler(entity, null); 51 } 52 if (eventPropertyChanging != null) 53 { 54 eventPropertyChanging.RemoveEventHandler(entity, null); 55 } 56 }