LINQ那些事儿(1)- 定义从关系数据库到entity class的映射
和多数O/R框架一样, LINQ2SQL可以通过Attribute标签定义和XML映射文件,两种方式来实现关系数据到实体类的映射。在MSDN上有关于这两种方法的详细介绍,本文只是作为快速向导。
在LINQ2SQL中,所有的数据操作的入口都是DataContext对象,如下面的代码示例了访问Northwnd数据库的Customer数据:
class Program { static void Main(string[] args) { using(var context = CreateContext()) { context.Log = Console.Out; var customers = context.GetTable<Customer>().Take(10); foreach (var item in customers) { Console.WriteLine(item.CompanyName); } } } static DataContext CreateContext() { var path = System.IO.Path.Combine( AppDomain.CurrentDomain.BaseDirectory, "northwnd.xml"); var connectionString = System.IO.Path.Combine( AppDomain.CurrentDomain.BaseDirectory, "northwnd.mdf"); var mapping = XmlMappingSource.FromXml(System.IO.File.ReadAllText(path)); var context = new DataContext(connectionString, mapping); return context; } }
更完整的通过DataContext实现SqlServer数据库的CRUD操作的方法,请参考LINQ那些事儿(2)- 简单对象的CRUD操作和Association的级联操作。CreateContext()函数通过传递数据库mdf文件的路径和映射信息,构造了一个DataContext对象,通过DataContext对象,我们可以对该数据库进行任何的操作,包括CRUD,甚至是删除或创建一个新的数据库文件。为了便于示例,本文用了Sqlexpress的本地数据库文件,你可以修改connectionString指向正式SqlSever上的数据库。
关于DataContext的详细说明,请参考MSDN:http://msdn.microsoft.com/zh-cn/library/system.data.linq.datacontext.aspx
我们来关注传递给DataContext构造函数的第二个参数——mapping,mapping对象中包含了Northwnd数据库和实体类之间的映射关系。LINQ2SQL通过System.Data.Linq.Mapping.MappingSource来作为映射关系的基类,并且在.Net Framework 3.5中提供了AttributeMappingSource和XmlMappingSource,分别表示了两种定义映射关系的方法——通过在实体类上用Attribute标签来定义,以及通过外部Xml文件来定义映射关系。
当使用一些开源的ORM框架时,你可能不得不手写定义这些映射信息,或者通过第三方的工具来实现映射信息的生成。对于LINQ2SQL,同样可以用手写定义,但是微软已经为我们提供了足够好的生成工具——O/R Designer和SqlMetal。
参考资料:
基于属性的映射http://msdn.microsoft.com/zh-cn/library/bb386971.aspx
使用O/R Designer生成对象模型 http://msdn.microsoft.com/zh-cn/library/bb384429.aspx
使用SqlMetal.exe生成对象模型http://msdn.microsoft.com/zh-cn/library/bb386987.aspx
通过O/R Desginer或SqlMetal,你不但可以生成实体类的定义,而且还生成了一个DataContext的派生类,名称为xxxDataContext(xxx为默认数据库的名称,也可以自行定义)。在文章开始的代码中,我们通过DataContext.GetTable<Customer>()来获取操作Customer表的表对象,但在xxxDataContext类中提供了更方便的方法,通过访问xxxDataContext类中包含的Customers属性即可。
需要注意的是,在SqlServer中你允许设计一张没有主键标识(Primary key)的数据表,但是在定义entity class的属性时,必须至少包含一个的主键属性(IsPrimaryKey=true)。这不单是数据库设计标准的要求,DataContext对象会使用PrimaryKey属性值作为实体对象的唯一标识,用来进行实体对象的生命周期管理,详见LINQ那些事(6)。
我不建议你使用手写的方法来定义entity class,甚至是必须用O/R Designer或Sqlmetal来生成entity class,因为对于包含关联关系(Association)的entity class,自动生成的代码中还包含了维护Association的代码,这对LINQ2SQL实现级联操作是非常关键的(你可以看看生成的Customer类的代码,它如何维护Orders属性)。
还有一个问题是通过Attribute标签和Xml映射文件来定义映射关系,孰优孰劣的问题,这已经是一个老问题了。听到最多的是,有人说大项目用XML方式,小项目用Attribute方式,我觉得那纯粹是瞎扯淡,但XML方式的确有一个好处就是有时当数据库发生更改时,我们直接修改XML就可以了,而无需重新编译代码,其他的更多就是习惯问题了。在这一系列的文章中,我都采用了XML的方式来定义,文章开始的代码示例了如何由XML来创建DataContext对象,你只需把DataContext改成xxxDataContext即可。
顺便提供几个非常常用的sqlmetal参数组合:(拷贝时注意去掉northwnd.和cs之间的断行)
- 1、生成本地数据库文件的映射:sqlmetal "northwnd.mdf" /code:northwnd.
cs /map:northwnd.xml /namespace:LinqAttach /context:Northwnd /pluralize - 2、通过链接字符串:sqlmetal /conn:”server=myserver; database=northwind” /code:northwnd.
cs /map:northwnd.xml /namespace:LinqAttach /context:Northwnd /pluralize - 3、通过指定数据源:sqlmetal /server:myserver /database:northwnd /password:pwd /code:northwnd.
cs /map:northwnd.xml /namespace:LinqAttach /context:Northwnd /pluralize
说明:
/code:指定包含生成实体类和派生DataContext类的cs代码的文件路径
/map:指定生成xml映射文件路径
/namespace:指定生成的cs代码所在的命名空间
/context:指定生成的派生DataContext类的类名
/pluralize:指定sqlmetal根据英文单/复数规则来生成实体类和属性的名称,非常靠谱。
链接
1、 LINQ那些事儿(1)- 定义从关系数据库到Entity Class的映射
2、 LINQ那些事儿(2)- 简单对象的CRUD操作和Association的级联操作
4、 LINQ那些事儿(4)- Query Expression和Query Operator
6、 LINQ那些事儿(6)- DataContext的对象生命周期管理
7、 LINQ那些事儿(7)- 通过自定义IEnumerable<T>来扩展LINQ
8、LINQ那些事儿(8)- 通过自定义IQueryable<T>和IQueryableProvider来扩展LINQ
All the posts in this blog are provided "AS IS" with no warranties, and confer no rights. Except where otherwise noted, content on this site is licensed under a Creative Commons Attribution 2.5 China Mainland License.