LINQ to SQL provides a run-time infrastructure for managing relational data as objects. In LINQ to SQL, the data model of a relational database is mapped to an object model expressed in the programming language of the developer. When you execute the application, LINQ to SQL translates language-integrated queries in the object model into SQL and sends them to the database for execution. When the database returns the results, LINQ to SQL translates them back into objects that you can manipulate.
LINQ to SQL includes support for stored procedures and user-defined functions in the database, and for inheritance in the object model.
从上面的描述我们可以看出来LINQ to SQL实际上是ORM结构的,LINQ to SQL 会将对象模型中的语言集成查询转换为 SQL,然后将其发送到数据库进行执行。 数据库返回结果时,LINQ to SQL 会将结果转换回可操作对象。在展开下面的话题之前,大家需要做点准备工作,先创建一个DB,添加一个表,DB设计成什么样对下面的讲解的内容影响不大,闲话不多说,接下来直接上干货儿。
1.创建Object Model
Object Model是根据数据库结构创建的,每个表对应一个类,DB对应一个类,该类继承System.Data.Linq.DataContext,如果自己手动编写,规模比较小的DB的工作量还好说,如果表多的话,那手动编写这部分代码就太累了,根据微软官方的介绍,有两种tools可以根据DB生产Object Model,Object Relational Designer和SQLMetal,Object Relational Designer是VS中自带的IDE,本文里只对Object Relational Designer的时候进行介绍。
a.右键工程,add new item,选择LINQ to SQL Classes
b.在Server Explorer中右键Data Connections,Add Connection,添加之前准备的DB,之后将DB中的表拖拽到.dbml界面中2的部分,如果DB中有存储过程,拖拽到.dbml界面界面中3的部分
完成以上操作后会在.dbml下的cs文件中自动生产Object Model code
2.如何调用自动生产的Object Model code
1 using (HerosOMDataContext ctx = new HerosOMDataContext("server=XXXXX;database=XXXX;uid=XX;pwd=XXXXX")) 2 { 3 var hh = from h in ctx.Heros 4 where h.StateId == 2 5 select h; 6 List<Hero> hList = hh.ToList<Hero>(); 7 int maxId = (from h in ctx.Heros 8 orderby h.Id 9 select h.Id).Max(); 10 int wuStateId = (from s in ctx.States 11 where s.Name == "Wu" 12 select s.Id).SingleOrDefault(); 13 int shuStateId = (from s in ctx.States 14 where s.Name == "Shu" 15 select s.Id).SingleOrDefault(); 16 int weiStateId = (from s in ctx.States 17 where s.Name == "Wei" 18 select s.Id).SingleOrDefault(); 19 ctx.Heros.InsertOnSubmit(new Hero { Id = maxId + 1, Name = "GanNing", Weapon = "Dao", StateId = wuStateId }); 20 ctx.SubmitChanges(); 21 ctx.Heros.DeleteAllOnSubmit(from h in ctx.Heros 22 where h.Name == "ZhouYu" 23 select h); 24 ctx.SubmitChanges(); 25 Hero hero = ctx.Heros.Where(h => h.Name == "XiaHouDun").FirstOrDefault(); 26 hero.Weapon = "DaDao"; 27 ctx.SubmitChanges(); 28 29 ctx.PROC_DeleteState(wuStateId, "Wu"); 30 ctx.ExecuteCommand("insert into State (Id,Name,Master) values ({0}, {1}, {2})", 1, "Wu", "SunQuan"); 31 }
第一行代码既是继承System.Data.Linq.DataContext的类,我们通过构造HerosOMDataContext类,来指定连接哪个DB,2-13行的代码和之前文章中讲到的Linq的用法并没有什么不同,唯一的区别就是操作的数据集合不同而已,既然是针对SQL,所以对于SQL有的增,删,改,查是少不了的。
a.增
上面示例代码中的14-15行对应的就是添加操作,从调用方式看,和我们平时往集合中插入操作没什么区别,唯一的区别就是调用InsertOnSubmit(TEntity entity)后,添加的object不会立刻加入到数据库里,只有接着调用方法SubmitChanges()后,才会真正的在DB中执行“增”操作,如果对于SQL server中执行的是什么样的语句比较好奇,可以使用SQL Server Profiler监控下。
b.删
上面示例代码中的16-19行对应的就是删除操作,从使用方法上没有什么需要特别注意的,依然是在调用方法SubmitChanges()后,才会真正的在DB中执行“删”操作。
c.改
上面示例代码中的20-22行对应的就是修改操作,先获取需要修改的对象,之后更新需要修改的属性,最后依然是在调用方法SubmitChanges()后,才会真正的在DB中执行“改”操作。
d.查
上面示例代码中的2-13行对应的就是修改操作,这一部分的使用方法和之前文章介绍的Linq的使用没有什么区别,和Linq to object和Linq to xml时一样,查询是异步的,只有真正调用时才会执行。
e.执行存储过程
上面示例代码中的24行对应的就是执行DB中的存储过程,在Object Relational Designer中拖拽DB中里的存储过程后,会在DataContext类中自动生产一个与存储过程同名的方法,方法的参数与存储过程中定义的参数相同,在执行存储过程时不需要调用方法SubmitChanges(),在调用存储过程同名的对应方法时,会立即在DB中执行该存储过程。
f.直接执行SQL语句
上面示例代码中的25行中调用的方法ExecuteCommand(string command, params object[] parameters),给用户提供了直接执行SQL语句的接口,另外方法ExecuteQuery也是类似的功能。
g.Attach
Use the Attach methods with entities that have been created in one DataContext, serialized to a client, and then deserialized back (with the intention to perform an update or delete operation). For more information, see Data Retrieval and CUD Operations in N-Tier Applications (LINQ to SQL).
Do not try to Attach an entity that has not been detached through serialization. Entities that have not been serialized still maintain associations with deferred loaders that can cause unexpected results if the entity becomes tracked by a second data context.
When a new entity is attached, deferred loaders for any child collections (for example, EntitySet collections of entities from associated tables) are initialized. When SubmitChanges is called, members of the child collections are put into an Unmodified state. To update members of a child collection, you must explicitly call Attach and specify that entity.
可以这么去理解上面的介绍,通过两个DataContext分别获取的实体,起生命周期只限于自己的DataContext里,如果想把当前的DataContext里得到的实体用在另一个DataContext里,就需要通过attach给这个实体“续命”,让他在新的DataContext里继续“活着”,前面用生命周期来解释实际是不准确的,但是这样的说法可能理解起来更简单点,结合下面的示例文件能更容易理解点
1 //通常,通过从其他层反序列化XML获取要附加的实体 2 //此示例使用 LoadWith 在一个查询中预先加载客户和订单, 3 //并禁用延迟加载 4 Customer cust = null; 5 using (NorthwindDataContext tempdb = new NorthwindDataContext()) 6 { 7 DataLoadOptions shape = new DataLoadOptions(); 8 shape.LoadWith<Customer>(c => c.Orders); 9 //加载第一个客户实体及其订单 10 tempdb.LoadOptions = shape; 11 tempdb.DeferredLoadingEnabled = false; 12 cust = tempdb.Customers.First(x => x.CustomerID == "ALFKI"); 13 } 14 Order orderA = cust.Orders.First(); 15 Order orderB = cust.Orders.First(x => x.OrderID > orderA.OrderID); 16 using (NorthwindDataContext db2 = new NorthwindDataContext()) 17 { 18 //将第一个实体附加到当前数据上下文,以跟踪更改 19 db2.Customers.Attach(cust); 20 //附加相关订单以进行跟踪; 否则将在提交时插入它们 21 db2.Orders.AttachAll(cust.Orders.ToList()); 22 //更新客户的Phone. 23 cust.Phone = "2345 5436"; 24 //更新第一个订单OrderA的ShipCity. 25 orderA.ShipCity = "Redmond"; 26 //移除第二个订单OrderB. 27 cust.Orders.Remove(orderB); 28 //添加一个新的订单Order到客户Customer中. 29 Order orderC = new Order() { ShipCity = "New York" }; 30 cust.Orders.Add(orderC); 31 //提交执行 32 db2.SubmitChanges(); 33 }
h.冲突处理
因为是操作SQL数据库,所以不可避免的会有多线程的问题,随之而来的也就有冲突的问题产生,这部分不具体介绍,感兴趣的可以看下下面链接里面的内容
https://msdn.microsoft.com/en-us/library/bb399389(v=vs.90).aspx
未完待续......