1、Entity Data Model (EDM) 深入分析, Part 1 Entity Data Model是.NET Framework v3.5 SP1引入的新功能,比Linq To SQL更加强大的ORM,让开发人员只需要着眼于领域对象模型的开发,而不需要考虑它们是如何与关系数据库交互。本系列文章逐步深入介绍如下内容:EDMX Schema 文件、Model Browser、映射关系、产生的实体类(Generated entity classes)、文档(Documentation)等等。 1. EDMX Schema 文件 可以将EDMX作为XML文件打开,你会发现该文件
2、包含3个主要部分。 Conceptual Models (CSDL) Storage Models (SSDL) Mapping (MSL) 一般情况下,你没有必要手动修改EDMX -XML文件。可视化的EDM 设计器、Mapping Details窗口和Model Browser 窗口包含有上述3个部分,并非常友好地显示整个Entity Data Model模型。 当你编译项目时,MSBuild 将从EDMX文件提取CSDL/SSDL/MSL内容,并放置3个独立的XML文件到项目的输出目录。 2. Model Browser 窗口 Model Browser窗口
3、以可视的树形图显示概念模型和存储模型。 3. Mapping details 窗口 EDM设计器也提供了一个不错的Mapping Details 窗口,包含2个视图。 Map Entity to Tables / View 这一视图显示了数据库中所有字段和相应实体中的属性,可以用来查看和编辑EDM的映射关系。 Map Entity to Functions 这一视图用来选择一个特定的存储过程来插入、更新或删除Entity实例。 4. 生成的实体类(Generated Entity Classes) 除了上述的XML Schem
4、a文件外,EDM向导也生成了实体类。下一步仔细分析.Designer.cs文件中的实体类,并和LINQ to SQL中的类进行比较。 1) 比较 LINQ to SQL class 和 EDM EntityObject class // LINQ to SQL [Table(Name="dbo.Employees")] public partial class Employee : INotifyPropertyChanging, INotifyPropertyChanged EDM类则是以不同的attributes,并且总是继承EntityObject或ComplexObj
5、ect 类。EntityObject 类提供了变更跟踪和关系管理。 // Entity Data Model [global::System.Data.Objects.DataClasses.EdmEntityTypeAttribute(NamespaceName="NorthwindModel", Name="Employee")] [global::System.Runtime.Serialization.DataContractAttribute()] [global::System.Serializable()] public partial class Employee :
6、 global::System.Data.Objects.DataClasses.EntityObject
2) 比较LINQ to SQL entity constructor 和 EDM Create method
// LINQ to SQL
public Employee()
{
this._Employees = new EntitySet
7、Territories = new EntitySet
8、Employee1 = default(EntityRef
9、loyee.EmployeeID = employeeID; employee.LastName = lastName; employee.FirstName = firstName; return employee; } 3) 比较LINQ to SQL 和 EDM : 实体属性(entity property) // LINQ to SQL [Column(Storage="_EmployeeID", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, I
10、sDbGenerated=true)] public int EmployeeID { get { return this._EmployeeID; } set { if ((this._EmployeeID != value)) { this.OnEmployeeIDChanging(value); this.SendPropertyChanging(); this._EmployeeID = value; this.SendPropertyChanged("EmployeeID"); this.OnEmployeeIDC
11、hanged(); } } } 尽管EDM公有属性(public property)的attribute是不同的,但get和set 基本是一样的。 // Entity Data Model [global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute(EntityKeyProperty=true, IsNullable=false)] [global::System.Runtime.Serialization.DataMemberAttribute()] public int EmployeeID
12、 { get { return this._EmployeeID; } set { this.OnEmployeeIDChanging(value); this.ReportPropertyChanging("EmployeeID"); this._EmployeeID = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value); this.ReportPropertyChanged("EmployeeID");
13、
this.OnEmployeeIDChanged();
}
}
4) 比较LINQ to SQL Table 和 EDM ObjectQuery
// LINQ to SQL
public System.Data.Linq.Table
14、Type的计划EntitySet。
// Entity Data Model
[global::System.ComponentModel.BrowsableAttribute(false)]
public global::System.Data.Objects.ObjectQuery
15、
return this._Employees;
}
}
private global::System.Data.Objects.ObjectQuery
16、q.DataContext EDM有一个类似于LINQ to SQL DataContext 的ObjectContext类,ObjectContext 类是负责与EDM 中实体类型交互的基本类。ObjectContext用来创建数据库连接、检索数据、持久化对象、以及对数据库的插入、更新和删除操作。 // Entity Data Model public partial class NorthwindEntities : global::System.Data.Objects.ObjectContext ObjectContext的连接字符串指向元数据(CSDL/SSDL/MSL
17、文件)和数据源(数据库连接字符串)。 connectionString="metadata=.NorthwindModel.csdl|.NorthwindModel.ssdl|.NorthwindModel.msl; provider=System.Data.SqlClient;provider connection string=" Data Source=SQLEXPRESS; Initial Catalog=Northwind; Integrated Security=True; MultipleActiveResultSets=True"" 5. Doc
18、umentation 属性
EDM中的实体类型(EntityTypes)、关联和属性有一个Documentation属性,对LINQ to SQL而言,这是一个新的属性。
Documentation属性将更新生成的partial实体类的XML注释,可以用来生成代码文档的帮助文件。
///
19、KeyProperties> [global::System.Data.Objects.DataClasses.EdmEntityTypeAttribute(NamespaceName="NorthwindModel", Name="Employee")] [global::System.Runtime.Serialization.DataContractAttribute()] [global::System.Serializable()] public partial class Employee : global::System.Data.Objects.DataClasses.
20、EntityObject 英文链接: 1. ADO.NET Entity Framework & LINQ to Entities, http://www.scip.be/index.php?Page=ArticlesNET12 Entity Data Model (EDM) 深入分析, Part 2 实体 SQL (Entity SQL),它是一种新的 SQL 语言,其中加入了之前的 SQL 语言并不支持的基于概念的查询功能。ESQL 扩展现有 SQL 语言的方式与 EDM 扩展数据库中所使用的关系模型的方式十分类似。此外,ESQL 未绑定到任何特定于后台数据库的语法,
21、因此可一次性编写查询(和/或应用程序),无论针对的是哪个后台数据库都无影响。 Entity SQL 是基于文本的、面向集合的、延后绑定的查询语言,也受到了T-SQL的影响。可以使用Entity SQL 创建对EDM的查询,Entity SQL 既可以通过Object Services components来执行,也可以通过Entity Client components 来执行。Entity SQL 设计的非常灵活,因此也变得有些复杂。本篇文章侧重于不同的查询技术,仅仅使用简单的查询,不包含复杂的条件、关联和聚合公式。 本系列文章上一篇: Entity Data Model
22、EDM) 深入分析, Part 1
1. 使用ObjectQuery
23、teQuery
24、
var query = context.CreateQuery
25、dEntities();
var sql = "NorthwindEntities.Employees";
ObjectQuery
26、E emp FROM NorthwindEntities.Employees AS emp " +
"WHERE emp.Country = 'USA'";
var query = context.CreateQuery
27、E emp FROM NorthwindEntities.Employees AS emp " +
"WHERE emp.Country = @country";
var query = context.CreateQuery
28、mp " +
"WHERE emp.Country = @country";
ObjectQuery
29、
"WHERE emp.Country = @country";
var query = context.CreateQuery
30、re("it.Country = @country", new ObjectParameter("country", "USA"));
3. ObjectQuery
31、ountry = @country";
var query = context.CreateQuery
32、 = @id";
var query = context.CreateQuery
33、ew ObjectParameter("id", 1)).First();
Console.WriteLine(country);
4. ObjectQuery
34、thwindEntities.Employees AS emp ";
var query = context.CreateQuery
35、var query = context.CreateQuery
36、前使用的 ADO.NET 提供程序非常类似,它将提供第一个抽象,可允许开发人员使用标准的 Connection、Command 和 DataReader 对象依照 EDM 执行查询。它还会将映射域模型所需的客户端视图引擎(根据 EDM 定义的)添加到底层关系数据库架构。必要时,EntityClient 可借助 ESQL 查询字符串让开发人员以行和列的形式处理实体,而不必生成类来表示概念架构。 1. EntityCommand 查询返回实体类型 Entity SQL也可以通过EntityClient 来执行,尽管代码比较啰嗦,但是在某些情况下,也是优点。 1) 首先创建Enti
37、tyConnection,重用Northwind data context 的连接字符串,并打开连接。 2) 创建 EntityCommand 对象,并传入Entity SQL语句和数据库连接对象。 3) 创建DbDataReader对象,并循环读取返回的结果集。 NorthwindEntities context = new NorthwindEntities(); EntityConnection conn = new EntityConnection(context.Connection.ConnectionString); conn.Open(); va
38、r sql = "SELECT VALUE emp FROM NorthwindEntities.Employees AS emp"; EntityCommand cmd = new EntityCommand(sql, conn); DbDataReader reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess); while (reader.Read()) { Console.WriteLine("{0} {1} {2} {3}", reader["EmployeeID"], reader["LastNam
39、e"], reader["FirstName"], reader["Country"]); } 当时使用SequentialAccess的DbDataReader时,需要小心访问数据,务必有序的读取。 如你改变成员的顺序,将抛出InvalidOperationException 异常 - "Attempt to read from column ordinal '0' is not valid. With CommandBehavior.SequentialAccess, you may only read from column ordinal '2' or greate
40、r." Console.WriteLine("{0} {1} {2} {3}", reader["LastName"], reader["EmployeeID"], reader["FirstName"], reader["Country"]); 2. EntityCommand 查询返回匿名类型 采用相同的技术可以实现返回匿名类型。 EntityConnection conn = new EntityConnection(context.Connection.ConnectionString); conn.Open(); var sql = "SELECT
41、 emp.LastName, emp.FirstName " + "FROM NorthwindEntities.Employees AS emp"; EntityCommand cmd = new EntityCommand(sql, conn); DbDataReader reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess); while (reader.Read()) { Console.WriteLine("{0} {1}", reader["LastName"], reader
42、["FirstName"]); } 3. EntityCommand 带参数查询 EntityCommand 带参数也比较容易,在Entity SQL字符串中参数名称以@作为前缀,接着创建EntityParameter对象,并增加到EntityCommand 的Parameters集合内。 EntityConnection conn = new EntityConnection(context.Connection.ConnectionString); conn.Open(); var sql = "SELECT VALUE emp FROM NorthwindEnt
43、ities.Employees AS emp " + "WHERE emp.Country = @country"; EntityCommand cmd = new EntityCommand(sql, conn); EntityParameter param = new EntityParameter("country", DbType.String); param.Value = "USA"; cmd.Parameters.Add(param); DbDataReader reader = cmd.ExecuteReader(Command
44、Behavior.SequentialAccess); while (reader.Read()) { Console.WriteLine("{0} {1} {2} {3}", reader["EmployeeID"], reader["LastName"], reader["FirstName"], reader["Country"]); } LINQ to Entities LINQ是在.NET v3.5 引入的新技术。相对于前面的Entity SQL而言,我更偏爱LINQ to entities。LINQ查询虽然有一些局限,但是LINQ更容易、更自然,此外,
45、还支持强类型,因此智能提示能帮助编写LINQ查询脚本。 LINQ to Entities 与LINQ to Objects和LINQ to SQL 基本一样,因此下面简单演示2个基本的LINQ to Entities的查询。 1. LINQ 带参数查询 NorthwindEntities context = new NorthwindEntities(); string country = "USA"; var query = from e in context.Employees where e.Country == country
46、 select e; foreach (var emp in query) Console.WriteLine("{0} {1} {2} {3}", emp.EmployeeID, emp.FirstName, emp.LastName, emp.Country); 2. LINQ 查询返回匿名类型 NorthwindEntities context = new NorthwindEntities(); var query = from e in context.Employees select new { e.LastNa
47、me, e.FirstName }; foreach (var emp in query) Console.WriteLine("{0} {1}", emp.LastName, emp.FirstName); 这篇文章对Entity Data Model 和Entity Framework 提供了各种查询技术进行了简单的介绍,希望对你有帮助。下一篇文章将介绍更高级的 Entity SQL 查询技术、查看SQL 语句、eager loading、变更跟踪、并发… 等等。 ADO.NET Entity Framework 深入分析, Part 4 Entity Data Mo
48、del 是一个概念模型,所有Entity SQL和LINQ to Entities 查询将最终转化为T-SQL的脚本,从数据库中查询数据。这里演示了几种方法来查看生成的T-SQL,有助于Debug或分析问题。 1. 使用SQL Server Profiler 工具 与LINQ to SQL比较而言,ObjectContext 类没有提供Log属性或者通用的log机制,因此,无法在Visual Studio 中跟踪所有的T-SQL语句。 如果你想查看所有执行的T-SQL语句,你需要使用SQL Server的Profiler 工具,关于具体如何使用SQL Server Profi
49、ler工具,请参考如下文章: SQL Profiler: Features, functions and setup in SQL Server 2005 2. ToTraceString 方法 另外一种方法去查看生成的T-SQL语句的方法,包括 EntityCommand和ObjectQuery类都有一个ToTraceString() 方法。在一些情况下,可以用来查看内部到底生成什么SQL脚本,而不必一定要使用SQL Server Profiler 工具。需要注意的是:ToTraceString() 方法实际上没有执行查询操作,仅仅是转化查询为SQL脚本。 通过增加一个断点,你可以轻松查看SQL脚本,需要记住的是:事先需要打开数据库连接,否则会抛出InvalidOperationException 异常(Execution of the command requires an open and available connection. The connection’s current state is closed.)






