您的位置:知识库 » 数据库

走进Linq-Linq to SQL源代码赏析 Table的获取过程

作者: 横刀天笑  来源: 博客园  发布时间: 2008-09-24 12:01  阅读: 9360 次  推荐: 0   原文链接   [收藏]  

系列文章导航:

走进Linq--Linq横空出世篇

走进Linq-辉煌的背后

走进Linq-Linq大观园

不能不说的C#特性-对象集合初始化器

不能不说的C#特性-匿名类型与隐式类型局部变量

不能不说的C#特性-扩展方法

不能不说的C#特性-匿名方法和Lambda表达式

不能不说的C#特性-迭代器(上)及一些研究过程中的副产品

不能不说的C#特性-迭代器(下),yield以及流的延迟计算

走进Linq-Linq to Objects(上)基础篇

走进Linq-Linq to Objects(下)实例篇

走进Linq-Linq to SQL感性认识篇

走进Linq-Linq to SQL How do I(1)

走进Linq-Linq to SQL How do I(2)

走进Linq-Linq to SQL How do I(3)

走进Linq-How do I(4)拾遗补零篇第一节

走进Linq-Linq to SQL源代码赏析 Table的获取过程

走进Linq-Linq to SQL源代码赏析之Provider的初始化

走进Linq-Linq to SQL源代码赏析,通过Linq to SQL看Linq


代码中的注释说的很详细了,先看看DataContext类里是否有Table<TEntity>的属性,而只有在强类型的DataContext情况下才会有的。所以只有在强类型的情况下才会在初始化DataContext的时候设置这些Table<TEntity>属性的值,从本篇后面的介绍可以看到,获取Table<TEntity>还不是个简单的事情,性能损耗比较大,所以框架默认提供的DataContext比强类型的DataContext更轻型,在上一章中有人问到DataContext是不是轻型的,我觉得如果使用框架提供的是很轻型的,实例化一个没有什么大的性能消耗。下面来看我们经常调用的GetTable方法:

public Table<TEntity> GetTable<TEntity>() where TEntity : class
{
     
this.CheckDispose();
     
//调用MetaModel的GetTable方法获得MetaTable对象
      
//MetaModel代表的是数据库和DataContext之间的映射
      
//而MetaModel代表的是表和对象之间的映射
      MetaTable metaTable = this.services.Model.GetTable(typeof(TEntity));
     
if (metaTable == null)
     {
          
throw Error.TypeIsNotMarkedAsTable(typeof(TEntity));
     }
     
//调用本类的GetTable方法
       ITable table = this.GetTable(metaTable);
      
//关于这里的ITable接口和ElementType属性有更多的讨论
            if (table.ElementType != typeof(TEntity))
            {
                
throw Error.CouldNotGetTableForSubtype(typeof(TEntity),
                        metaTable.RowType.Type);
            }
            
return (Table<TEntity>)table;
        }

        
private ITable GetTable(MetaTable metaTable)
        {
            ITable table;
            
//先查看字典中是否有这个table,该字典是以MetaTable为key,以ITable为value的
            if (!this.tables.TryGetValue(metaTable, out table))
            {
                
//通过检查表之间的关联难验证表的合法性
                ValidateTable(metaTable);
                
//反射ITable对象
                table = (ITable)Activator.CreateInstance(typeof(Table<>).
MakeGenericType(
new Type[] { metaTable.RowType.Type }),
BindingFlags.NonPublic 
| BindingFlags.Public | BindingFlags.Instance,
nullnew object[] { this, metaTable }, null);
       
//通过反射获取ITable对象后,还将其存储在字典中,可以看到这个字典起一个缓存的作用
        
//以后就可以直接从字典里取了,也就是这个GetTable的过程并不是每次都有反射的性能损耗
                this.tables.Add(metaTable, table);
            }
            
return table;
}

MetaTable metaTable = this.services.Model.GetTable(typeof(TEntity));

这一句是调用MetaModelGetTable方法,MetaModel根据映射的不同有两种实现:AttributeMetaModelMappedMetaModel

得到MetaTable对象后,就可以调用Table<TEntity>的构造函数来获取Table<TEntity>对象了,但是这里却使用的是反射:

table = (ITable)Activator.CreateInstance(typeof(Table<>).MakeGenericType(new Type[] { metaTable.RowType.Type }), BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, new object[] { this, metaTable }, null);

为什么不直接new呢?原来微软将Table<TEntity>的构造函数设置为私有的了,无法直接使用new调用,

在这里除了构造函数是私有的外,最主要的原因是Table<>是一个泛型类,而这个时候还不知道具体的泛型参数,所以我们只能用泛型了,也就是说即使这里构造函数是私有的,我们也只能用反射构建Table<>的实例。谢谢IVony的提醒。但是这也并不妨碍后面使用的变形的单件模式。

也许是为了防止客户代码任意的创建Table<TEntity>对象,而将构造函数设为私有的吧,也许有人会马上想到,这里应该使用单件模式啊,防止客户端任意创建实例。

0
0

数据库热门文章

    数据库最新文章

      最新新闻

        热门新闻