下面是简单的描述
MetaModel
|
MetaTable/ MetaFunction
|
MetaType
|
MetaDataMember
位于最顶部的是MetaModel,它由DataContext的Mapping属性提供,MetaModel 中有多个MetaTable /MetaFunction,每个MetaTable中有一个RowType属性(即MetaType),MetaType由多个MetaDataMember组成.
在dbml或是linq to sql生成的代码中对应的东西,你都可以在这些metadata中找到, 因此,这部分数据可以作为应用程序框架的metadata. metadata是应用程序框架中最重要一环.我在使用中唯一感到不方便的是它没有明确的提供字符串类型的size,MetaDataMember的DbType属性总是类似这样的 (varchar(10)),你需要自己解析它,或者自行定义添加一个Size Attribute),由于代码生成的关系,这有点不方便. 同样,MetaTable.TableName也会表现出ower,如dbo.Quotation.
有点不太一致的地方是你在强类型的DataContext类中所看到的InsertXXX,UpdateXXX,DeleteXXX方法,其实都对应在每个具体的MetaTable中, 并没有如你所想的提供在MetaModel类中 ,MetaTable这个类提供了InsertMethod,UpdateMethod,DeleteMethod等MethodInfo类型的属性,同样,每个具体类的OnValidate,OnLoaded在MetaTable表也有对应的表示OnValidateMethod,OnLoadedMethod.
在具体的实现上,MetaTable 有两个具体的实现,AttributedMetaTable ,MappedTable ,这两个是内部的类型,当使用attributed 声明映射时将会使用AttributedMetaTable类型,而使用map 文件时,将会使用MappedTable . 有人有使用Attributed映射好还是xml文件映射好的疑问,其实当这些attributed还是xml转换为metadata表示后,其它的操作都是一样的,理论上linq to sql是不管是你使用那种方法映射的,因此,不存在两者性能谁好谁坏的问题.
上面所说的也同样反映在MetaFunction之上,同样的,它也有针对attributed和mapped的实现(AttributedMetaFunction,MappedMetaFunction)
btw : 在用reflector查看linq to sql 实现时,会发现一种非常常见的模式,就是先声明一个abstract class ,然后在内部声明一个或多个抽象类实现,这些实现都是不公开的. 这种设计方式通常用在不想过早实现接口,但又想做实现隐藏和分离的场合. 当然在.net 中,abstract class代替接口使用的场景还是比较多的,特别是在早期,由于com接口的负面影响,一些宣传中甚至有鼓励类代替接口的现象,这都是不恰当的.
下面这行代码表示只获取能保存并排除关系的所有成员
MetaType metaType=db.Mapping.GetTable(typeof(Quotation)).RowType;
var list=(from m in metaType.DataMembers where m.IsPersistent==true && m.IsAssociation==false select m).ToList();
下面这段测试代码演示如何使用xxxAccessor 来代替Reflect
MetaTable t = db.Mapping.GetTable(typeof(Quotation));
Quotation q=db.Quotation.FirstOrDefault();
MetaDataMember member=t.RowType.DataMembers.First(item => item.Name == "Id");
Assert.AreEqual(member.MemberAccessor.GetBoxedValue(q), q.Id);
string id = "test";
object obj = q;
member.MemberAccessor.SetBoxedValue(ref obj, id);
Assert.AreEqual(q.Id, id);
string id2 = "test2";
member.StorageAccessor.SetBoxedValue(ref obj, id2);
Assert.AreEqual(q.Id, id2);
上面这段测试的思想可以比较方便的为entity类提供一个this属性,让使用者通过字符串来取值或设置值.
综合所述, 除了作为应用程序metadata的提供者外,linq to sql 的metadata还可以用来有效的避免reflection,不知道大家还有其他用法没有.
感谢宋国安的提醒,其实上面还是漏了一些部分,即metadata是如何获取的,MappingSource是个抽象类,具体的实现类XmlMappingSource,AttributeMappingSource解决metadata 的读取问题
MappingSource
|
|
XmlMappingSource
AttributeMappingSource
DataContext有个构造方法DataContext(string fileOrServerOrConnection, MappingSource mapping)允许你传递一个特别的MappingSource 实现,显然,默认的,他总是使用AttributeMappingSource
如宋国安所说,dbml 和用于XmlMappingSource的xml文件是不同的, 得确,这两者是不同的,dbml 是代码生成的依据,事实上linq to sql 从来不直接使用dbml ,AtrributeMappingSource也只使用根据dbml生成后的代码,而mapped的xml,linq to sql有一个读取过程, 将 xml描述转换为metadata. 就个人而言,从来没有把两者混在一起.根本不同的东西,怎么混 . 由于两者最终的结果是一致的.所以更没有必要刻意去区分.