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根据英文单/复数规则来生成实体类和属性的名称,非常靠谱。

链接

LINQ那些事(总)

1、 LINQ那些事儿(1)- 定义从关系数据库到Entity Class的映射

2、 LINQ那些事儿(2)- 简单对象的CRUD操作和Association的级联操作

3、 LINQ那些事儿(3)- 事务和并发冲突处理

4、 LINQ那些事儿(4)- Query Expression和Query Operator

5、 LINQ那些事儿(5)- 动态查询

6、 LINQ那些事儿(6)- DataContext的对象生命周期管理

7、 LINQ那些事儿(7)- 通过自定义IEnumerable<T>来扩展LINQ

8、LINQ那些事儿(8)- 通过自定义IQueryable<T>和IQueryableProvider来扩展LINQ

posted @ 2009-12-31 23:37  海南K.K  阅读(1515)  评论(0编辑  收藏  举报