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

系列文章导航:

走进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是如何初始化的,它需要一个连接对象,还需要一个MappingSource做映射的配置。

DataContext中我们打交道最多的也许就是GetTable<TEntity>()方法了,这个方法会获取一个Table<TEntity>对象,今天我们就来看看这个对象是如何获取的。

对于获取Table<TEntity>对象我们还要看看这个DataContext是不是强类型的,关于强类型的DataContext可以看我前面一篇文章,强类型的DataContext里包含有几个Table<TEntity>类型的属性,比如我们的库中有blogsposts等数据库表,那么你可能就会建立Table<Blog>Table<Post>类型的属性(参见前面一篇文章)。在上一章DataContext的初始化里讲到Init方法的最后一行是InitTables方法的调用。我们首先来看看InitTables方法的代码:

/// <summary>
/// 初始化数据库中有几个表
/// 从方法实现中意图来看,这个方法主要在定义了强类型的DataContext才有意义
/// 在强类型的DataContext里一般定义了Table<Post>之类的字段来表示数据库中有几个
/// 表,该方法调用DataContext的GetTable方法设置这些字段的值
/// </summary>
/// <param name="schema"></param>
private void InitTables(object schema)
{
     
//用反射遍历DataContext类(可能是它的子类)里所有的公有实例字段
      foreach (FieldInfo info in schema.GetType().GetFields(BindingFlags.Public |
                  BindingFlags.Instance))
     {
        
//字段类型
         Type fieldType = info.FieldType;
        
//该字段是否是泛型的,并且是Table<>类型的,而且该字段的值为null
        if ((fieldType.IsGenericType && (fieldType.GetGenericTypeDefinition() ==
            typeof
(Table<>))) && (((ITable)info.GetValue(schema)) == null))
         {
              
//获取Table<TEntity>中TEntity的具体类型
                Type type = fieldType.GetGenericArguments()[0];
              
//调用DataContext的GetTable方法得到一个ITable对象
                ITable table = this.GetTable(type);
              
//设置值
                info.SetValue(schema, table);
          }
        }
}

系列文章导航:

走进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;
}

系列文章导航:

走进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


关于设计模式的旁白

为什么Table<TEntity>类不使用单件模式?

一个数据库中有几个表,对于每个表对象(Table<TEntity>)我们希望它是单例的,但是系统中并不是只存在一个表对象。在这里微软一方面将表对象的构造函数设为私有的来防止客户端任意的使用new构造表对象的实例,而且没有提供任何公开的接口获取这个实例,另外一方面在DataContext里有一个Dictionary<MetaTable, ITable> tables的字典,用于缓存表对象。

这样就有这样的个示例:

public class Table<TEntity>
    {
        
//私有的构造函数
        private Table()
        { }
    }
    
public class DataContext()
    {
        
private Dictionary<MetaTable, ITable> tables;

        
public DataContext()
        {
            
this.tables = new Dictionary<MetaTable,ITable>();
        }

        
public ITable GetTable(MetaTable metaTable)
        {
            ITable table 
= null;
            
if(!tables.TryGetValue(metaTable,out table)
            {
                
//获取table对象

                
//将刚刚获取的table对象缓存起来,以备后用
                tables.Add(metaTable,table);
            }
            
return table;
        }
}

it知识库走进Linq-Linq to SQL源代码赏析 Table的获取过程,转载需保留来源!

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。