ADO.NET Entity Framework & LINQ to Entities - deel 1
2010-11-10 11:49
537 查看
Some weeks ago Microsoft released Beta 3 of the ADO.NET
Entity Framework
(sometimes called ADO.NET vNext). Probably the
final version will be shipped during the first half of 2008 as an
update to the Visual Studio 2008 & .NET 3.5 release.
Update 20/10/2008
: Visual Studio 2008 & .NET 3.5
Service Pack 1 has been released in August 2008. This article has been
updated so all examples will work fine in the final version of the
Entity Framework.
The Entity Framework looks like a interesting technology which is
more powerful and advanced than LINQ to SQL. Both technologies have a
different kind of philosophy but several features have similar
implementations. The EF is more than just an ORM (Object Relational
Mapping) tool. It allows developers to query and manipulate data using a
conceptual model instead of a physical storage model. It will also
become the foundation of new application blocks like Astoria
(ADO.NET Data Services) which will enable you to expose any data store
as web services and Jasper
(Data Access Incubation Projects) which can be used to build dynamic data layers
.
This article will not explain all details about the Entity Framework
nor compare everything with LINQ to SQL. But I will try to create a
small tutorial on how to start with the Entity Framework using the
Northwind sample database. If possible I will refer to LINQ to SQL
features. This article will be the first in a series about the ADO.NET
Entity Framework and the LINQ to Entities querying language.
The
Entity Framework architecture
Installation
Generate
an Entity Data Model
The
Entity Data Model (EDM)
LINQ
to SQL Diagram vs. Entity Data Model
Names
of EntityTypes and EntitySets
Scheme
file (EDMX)
Model
Browser
Mapping
Details
Generated
entity classes
Documentation
Entity
SQL
ObjectQuery
queries which return entity types
ObjectQuery
queries with parameters
ObjectQuery
queries which return primitive types
ObjectQuery
queries which return anonymous types
EntityCommand
queries which return entity types
EntityCommand
queries which return anonymous types
EntityCommand
queries with parameters
LINQ
to Entities
LINQ
queries with parameters
LINQ
queries which return anonymous types
Part 2 :
View
SQL statements
SQL
profiling tools
ToTraceString
method
Tools
eSqlBlast
LINQPad
Part 3 :
Add,
update and delete entities
Update
(modify) an entity
Add (create)
and entity
Add
(create) entity with associated entities
Delete an
entity
Concurrency
handling
Set
ConcurrencyMode
Resolve
concurrency conflicts
Change
tracking
ObjectStateManager
Dump() &
DumpAsHtml() extension methods
NoTracking
option
Part 4 :
Querying
metadata
Download beta 3 of the ADO.NET Entity Framework from the Microsoft website
and install it. Make sure you
have installed Visual Studio 2008 RTM and the .NET 3.5 framework.
1) Start with a new console application
2) Add a new item. Choose the ADO.NET Entity Model
item. Give it the name NorthwindModel.edmx
.
3) The Entity Data Model Wizard
will be started.
Step 1/3 : Choose Model Contents
. Choose
Generate from database
.
![](http://www.scip.be/ImagesScreenshots/ArticleEF%20-%20EDM%20Wizard1.png)
4) Step 2/3 : Choose your data connection
. Select a
connection to the SQL Server Northwind database.
5) Step 3/3 : Choose your database objects
. Now you
can select all tables, views and stored procedures which should be
mapped in your conceptual model.
![](http://www.scip.be/ImagesScreenshots/ArticleEF%20-%20EDM%20Wizard2.png)
6) Finish the wizard. The Entity Data Model will be generated. An EDMX
file, which is the equivalent of DBML file in LINQ to SQL, will be
added to your project.
LINQ to SQL Object Relational Diagram
![](http://www.scip.be/ImagesScreenshots/ArticleEF%20-%20Diagram%20LINQ%20to%20SQL.png)
Entity Data Model (EDM)
![](http://www.scip.be/ImagesScreenshots/ArticleEF%20-%20Diagram%20LINQ%20to%20Entities.png)
Entity Data Model (EDM)
![](http://www.scip.be/ImagesScreenshots/ArticleEF%20-%20Diagram%20LINQ%20to%20Entities%20SP1.png)
The Entity Data Model diagram has a lot of similarities with a LINQ
to SQL diagram. An EDM entity is divided into 2 parts : the Scalar
Properties
and the Navigation Properties
. A NavigationProperty references another
EntityType
and it defines the direction of the relationship
(one-to-many, one-to-one, ...).
EDM associations use another visualization and they have other
properties then LINQ to SQL but they actually represent the same.
Update 20/10/2008
: In Visual Studio 2008 SP1 all
properties will be organized by alphabetical order.
By default, LINQ to SQL changes plural table
names to singular entity class names automatically. The EDM designer
does not do this. So the Northwind table Employees is mapped to an
EntityType called Employees. Be careful because this can lead to
confusion.
![](http://www.scip.be/ImagesScreenshots/ArticleEF%20-%20Names1.png)
So change the name of the EntityType manually :
![](http://www.scip.be/ImagesScreenshots/ArticleEF%20-%20Names2.png)
After changing the name, you will notice that the diagram is being
updated and IntelliSense now correctly shows ObjectQuery<Employee
>
NorthwindEntities.Employees when hovering the Employees EntitySet in a
LINQ to Entities query.
![](http://www.scip.be/ImagesScreenshots/ArticleEF%20-%20Names3.png)
Some simple name convention rules:
EntityType, Name -> single
EntityType, EntitySetName -> plural
NavigationProperty, 0..1, instance -> single
NavigationProperty, *, collection -> plural
If you would open the EDMX
file as XML, than you
will see that this file contains 3 major sections.
ConceptualModels
(CSDL)
StorageModels
(SSDL)
Mapping
(MSL)
[/code]
You do not have to modify this XML file manually. The Visual EDM
designer and the Mapping Details and Model Browser windows will combine
these 3 parts together and give you a nice visual representation of the
whole Entity Data Model.
When you build your project, MSBuild will extract the CSDL/SSDL/MSL
content from the EDMX
file and places these 3 seperate
XML files in your project output directory.
The EDM designer has also a nice Mapping Details
window. It consists of 2 views.
Map Entity to Tables / View
This view shows all fields in the database and the corresponding
properties in the entity. It can be used to view and edit mappings in
the Entity Data Model.
![](http://www.scip.be/ImagesScreenshots/ArticleEF%20-%20Mapping%20Details.png)
Map Entity to Functions
This view can be used to select a specialized stored procedure to
insert, update or delete an instance of the entity.
![](http://www.scip.be/ImagesScreenshots/ArticleEF%20-%20Mapping%20Details%20Functions.png)
In addition to this XML schema
file, the wizard has also generated entity classes.
Let's take a
closer look at these classes in the .Designer.cs
file
and compare them with the LINQ to SQL classes.
1) LINQ to SQL class vs EDM EntityObject class
[/code]
An EDM class uses different attributes and it is always inherited
from EntityObject
or ComplexObject.
The
EntityObject class provides change tracking and relationship
management. Of course this class also inherits from the
INotifyPropertyChanging and INotifyPropertyChanged interfaces so all
entities support two-way binding.
[/code]
2) LINQ to SQL entity constructor vs. EDM Create
[/code]
EDM does not generate a constructor like LINQ to SQL does. Instead it
creates a factory method with input parameters for all required (not
nullable) properties.
[/code]
3) LINQ to SQL vs. EDM : entity property
[/code]
The attributes of a public property are different in EDM but the get
and set accessors are almost the same.
[/code]
4) LINQ to SQL Table vs. EDM ObjectQuery
[/code]
In LINQ to SQL the GetTable method is called to return a collection
of entities. In EDM an Entity SQL query will be executed through a
Object Services component which returns an EntitySet of EntityTypes.
[/code]
5) LINQ to SQL DataContext vs. EDM ObjectContext
[/code]
EDM has an equivalent of the LINQ to SQL DataContext, namely an ObjectContext
.
The ObjectContext
class is the primary class for
interacting with data as objects that are instances of entity types
defined in the Entity Data Model. An ObjectContext can be used to make a
connection to the database, to retrieve data, to store the persistent
objects and to perform insert, update and delete actions on the
database.
[/code]
The connection string of an ObjectContext refers to the metadata
(CSDL/SSDL/MSL files) and the data source (database connection string).
[/code]
EntityTypes, Associations and Properties in the Entity Data Model
have a Documentation
property. This is new compared to
LINQ to SQL.
![](http://www.scip.be/ImagesScreenshots/ArticleEF%20-%20Documentation.png)
These documentation properties will update the XML comment of the
generated partial entity classes. This is great because it can be used
to generate code documentation help files with SandCastle.
[/code]
Entity SQL (E-SQL) is a text-based, collection-oriented and
late-bound query language which is influenced by Transact-SQL. It
allows you to create queries on the Entity Data Model. Entity SQL
statements can be executed with both Object Services components and
Entity Client components. It is quite elaborated and some things can
become complicated. In this first article I will only be focusing on
the various query techniques. So only simple queries without complex
conditions, without associations and without aggregates will be
demonstrated.
This example will show how to execute an Entity SQL query that
returns a collection of instances of one entity type.
1) First create a Northwind ObjectContext
instance.
2) The Entity SQL statements itself are string expressions. In most
cases they will be composed as SELECT-FROM
query
expressions. Use the VALUE
keyword
in
the SELECT clause to indicate that the entity should be flattened to a
row.
3) We will use some Object Services components to execute the query.
So call the CreateQuery<T>()
factory method of
the ObjectContext
. This will create an ObjectQuery
object which represents a query against the store. This query will be
formulated through the Entity SQL statement.
4) The Entity Framework uses deferred loading. So the SQL statement is executed at the point your code
explicitly needs the data.
In this case the query will be
executed in the first loop of the ForEach iteration.
[/code]
Instead of using the factory method CreateQuery<T>() you can
also create an ObjectQuery
object yourself. The second
parameter is the object context.
[/code]
Let's add a WHERE
clause :
[/code]
Parameters are variables that are defined outside Entity SQL but in
the query statement you have to define these parameter names with the at
(@) symbol as a prefix. Parameters have to be created as ObjectParameter
objects. They can be added to the ObjectQuery
instance.
So let us add a Country parameter :
[/code]
We can also do the same without using the CreateQuery<T>()
factory method.
[/code]
ObjectParameter
objects can also be passed to the CreateQuery<T>()
method.
[/code]
A third alternative is to use the Where
extension
method. Use the keyword it
to refer to the current
query statement.
[/code]
It is also possible to return a collection of primitive types instead of
entity types. Therefore you have to make sure that the SELECT clause
only returns 1 value. You also have to specify the primitive type in the
CreateQuery
method.
[/code]
[/code]
Besides using Entity SQL, you can also use a query builder method to
achieve the same result. Entity SQL provides a SelectValue
method which will skip the implicit row construction. Only one item may
be specified in a select value clause.
[/code]
It is also possible to do some data shaping and to create
ObjectQuery<T> queries which return anonymous types. Just change
the SELECT clause and use the DbDataRecord
class in the
CreateQuery
method. The DBDataRecord class was
introduced in .NET 1.0 and it provides data binding support for any kind
of enumeration.
[/code]
[/code]
Entity SQL can also be executed through EntityClient components. This
needs more plumbing but in some cases it can have advantages.
1) First create an EntityConnection
. I have re-used
the connectionstring of my Northwind data context. Open this connection.
2) Create an EntityCommand
object and pass the
Entity SQL statement and connection to it.
3) Create a DbDataReader
and loop through the
results of the command.
[/code]
When using a data reader with sequential access you always have to be
careful when accessing data. This should be done in sequential order !
e.g. When you change the order of the members/properties, you will
get an InvalidOperationException
. "Attempt to read
from column ordinal '0' is not valid. With
CommandBehavior.SequentialAccess, you may only read from column ordinal
'2' or greater.
"
Update 20/10/2008
: In Beta 3 all members/properties were
ordered according the order in the database. In SP1 all properties are
organized by alphabetical order. So in this example you should read
Country, EmployeeID, FirstName and LastName.
Data shaping with anonymous types can be done with just the same
techniques :
[/code]
Adding parameters can also be done easily. Add parameter names with
@-prefixes in the Entity SQL string and create EntityParameter
objects. Add them to the EntityCommand
object.
[/code]
LINQ was introduced in .NET 3.5 and I am still excited about this technology.
I prefer querying with LINQ to
Entities above Entity SQL. LINQ queries do have some restrictions but
they are easier, more natural and in addition they are strong-typed so
IntelliSense can help you creating queries.
LINQ to Entities is almost the same as LINQ to Objects and LINQ to
SQL. So I will just show 2 basic LINQ to Entities queries. Other
examples of LINQ queries can be found in several articles
on my website.
[/code]
[/code]
I hope that this walkthrough provides a good overview of the Entity
Data Model and the various querying techniques that the Entity
Framework provides. In the next parts of my series about the ADO.NET
Entity Framework I will try to cover more advanced Entity SQL query
techniques, viewing SQL statements, eager loading, change tracking,
concurrency, ... So stay tuned. If you have any remarks or suggestions,
please let me know.
Entity Framework
(sometimes called ADO.NET vNext). Probably the
final version will be shipped during the first half of 2008 as an
update to the Visual Studio 2008 & .NET 3.5 release.
Update 20/10/2008
: Visual Studio 2008 & .NET 3.5
Service Pack 1 has been released in August 2008. This article has been
updated so all examples will work fine in the final version of the
Entity Framework.
The Entity Framework looks like a interesting technology which is
more powerful and advanced than LINQ to SQL. Both technologies have a
different kind of philosophy but several features have similar
implementations. The EF is more than just an ORM (Object Relational
Mapping) tool. It allows developers to query and manipulate data using a
conceptual model instead of a physical storage model. It will also
become the foundation of new application blocks like Astoria
(ADO.NET Data Services) which will enable you to expose any data store
as web services and Jasper
(Data Access Incubation Projects) which can be used to build dynamic data layers
.
This article will not explain all details about the Entity Framework
nor compare everything with LINQ to SQL. But I will try to create a
small tutorial on how to start with the Entity Framework using the
Northwind sample database. If possible I will refer to LINQ to SQL
features. This article will be the first in a series about the ADO.NET
Entity Framework and the LINQ to Entities querying language.
The
Entity Framework architecture
Installation
Generate
an Entity Data Model
The
Entity Data Model (EDM)
LINQ
to SQL Diagram vs. Entity Data Model
Names
of EntityTypes and EntitySets
Scheme
file (EDMX)
Model
Browser
Mapping
Details
Generated
entity classes
Documentation
Entity
SQL
ObjectQuery
queries which return entity types
ObjectQuery
queries with parameters
ObjectQuery
queries which return primitive types
ObjectQuery
queries which return anonymous types
EntityCommand
queries which return entity types
EntityCommand
queries which return anonymous types
EntityCommand
queries with parameters
LINQ
to Entities
LINQ
queries with parameters
LINQ
queries which return anonymous types
Part 2 :
View
SQL statements
SQL
profiling tools
ToTraceString
method
Tools
eSqlBlast
LINQPad
Part 3 :
Add,
update and delete entities
Update
(modify) an entity
Add (create)
and entity
Add
(create) entity with associated entities
Delete an
entity
Concurrency
handling
Set
ConcurrencyMode
Resolve
concurrency conflicts
Change
tracking
ObjectStateManager
Dump() &
DumpAsHtml() extension methods
NoTracking
option
Part 4 :
Querying
metadata
The Entity
Framework architecture
![]() | The ADO.NET Entity Framework is a layered framework which abstracts the relational schema of a database and presents a conceptual model. Data Source : The bottom layer is the data which can be stored in one or many databases. Data Providers : The data will be accessed by a ADO.NET data provider. At this moment only SQL Server is supported but in the near future there will be data providers for Oracle, MySQL, DB2, Firebird, Sybase, VistaDB, SQLite, ... Entity Data Model (EDM) : The Entity Data Model consists of 3 parts : Conceptual schema definition language (CSDL) : Declare and define entities, associations, inheritance, ... Entity classes are generated from this schema. Store schema definition language (SSDL) : Metadata describing the storage container (=database) that persists data. Mapping specification language (MSL) : Maps the entities in the CSDL file to tables described in the SSDL file. Entity Client : EntityClient is an ADO.NET managed provider that supports accessing data described in an Entity Data Model. It is similar to SQLClient, OracleClient and others. It provides several components like EntityCommand, EntityConnection and EntityTransaction. Object Services : This component enables you to query, insert, update, and delete data, expressed as strongly-typed CLR objects that are instances of entity types. Object Services supports both Entity SQL and LINQ to Entities queries. Entity SQL (ESQL) : Entity SQL is a derivative of Transact-SQL, designed to query and manipulate entities defined in the Entity Data Model. It supports inheritance and associations. Both Object Services components and Entity Client components can execute Entity SQL statements. LINQ to Entities : This is a strong-typed query language for querying against entities defined in the Entity Data Model. Please check the MSDN pages about the ADO.NET Entity Framework for detailed information about all layers and components. There is also an interesting Entity Framework FAQ from Microsoft developer Danny Simmons. |
Installation
Download beta 3 of the ADO.NET Entity Framework from the Microsoft websiteand install it. Make sure you
have installed Visual Studio 2008 RTM and the .NET 3.5 framework.
Generate an Entity Data Model
1) Start with a new console application2) Add a new item. Choose the ADO.NET Entity Model
item. Give it the name NorthwindModel.edmx
.
3) The Entity Data Model Wizard
will be started.
Step 1/3 : Choose Model Contents
. Choose
Generate from database
.
![](http://www.scip.be/ImagesScreenshots/ArticleEF%20-%20EDM%20Wizard1.png)
4) Step 2/3 : Choose your data connection
. Select a
connection to the SQL Server Northwind database.
5) Step 3/3 : Choose your database objects
. Now you
can select all tables, views and stored procedures which should be
mapped in your conceptual model.
![](http://www.scip.be/ImagesScreenshots/ArticleEF%20-%20EDM%20Wizard2.png)
6) Finish the wizard. The Entity Data Model will be generated. An EDMX
file, which is the equivalent of DBML file in LINQ to SQL, will be
added to your project.
The Entity Data
Model (EDM)
LINQ to SQL Diagram
vs. Entity Data Model
LINQ to SQL Object Relational Diagram
![](http://www.scip.be/ImagesScreenshots/ArticleEF%20-%20Diagram%20LINQ%20to%20SQL.png)
Entity Data Model (EDM)
(Beta 3)
![](http://www.scip.be/ImagesScreenshots/ArticleEF%20-%20Diagram%20LINQ%20to%20Entities.png)
Entity Data Model (EDM)
(SP1)
![](http://www.scip.be/ImagesScreenshots/ArticleEF%20-%20Diagram%20LINQ%20to%20Entities%20SP1.png)
The Entity Data Model diagram has a lot of similarities with a LINQ
to SQL diagram. An EDM entity is divided into 2 parts : the Scalar
Properties
and the Navigation Properties
. A NavigationProperty references another
EntityType
and it defines the direction of the relationship
(one-to-many, one-to-one, ...).
EDM associations use another visualization and they have other
properties then LINQ to SQL but they actually represent the same.
Update 20/10/2008
: In Visual Studio 2008 SP1 all
properties will be organized by alphabetical order.
LINQ to SQL : | EDM : Association![]() |
Names of EntityTypes and
EntitySets
By default, LINQ to SQL changes plural tablenames to singular entity class names automatically. The EDM designer
does not do this. So the Northwind table Employees is mapped to an
EntityType called Employees. Be careful because this can lead to
confusion.
![](http://www.scip.be/ImagesScreenshots/ArticleEF%20-%20Names1.png)
So change the name of the EntityType manually :
![](http://www.scip.be/ImagesScreenshots/ArticleEF%20-%20Names2.png)
After changing the name, you will notice that the diagram is being
updated and IntelliSense now correctly shows ObjectQuery<Employee
>
NorthwindEntities.Employees when hovering the Employees EntitySet in a
LINQ to Entities query.
![](http://www.scip.be/ImagesScreenshots/ArticleEF%20-%20Names3.png)
Some simple name convention rules:
EntityType, Name -> single
EntityType, EntitySetName -> plural
NavigationProperty, 0..1, instance -> single
NavigationProperty, *, collection -> plural
Scheme file (EDMX)
If you would open the EDMXfile as XML, than you
will see that this file contains 3 major sections.
ConceptualModels
(CSDL)
StorageModels
(SSDL)
Mapping
(MSL)
<?xml version="1.0" encoding="utf-8" ?> <edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx" > <edmx:Runtime> <!-- CSDL content --> <edmx:ConceptualModels > <Schema Namespace="NorthwindModel" Alias="Self" xmlns="http://schemas.microsoft.com/ado/2006/04/edm" > <EntityContainer Name="NorthwindEntities" > <EntitySet Name="Employees" EntityType="NorthwindModel.Employee" /> <AssociationSet Name="FK_Orders_Employees" Association="NorthwindModel.FK_Orders_Employees" > <End Role="Employees" EntitySet="Employees" /> <End Role="Orders" EntitySet="Orders" /> </AssociationSet> </EntityContainer> <EntityType Name="Employee" > <Documentation><Summary>Employee entity which corresponds with the Northwind.Employees table</Summary></Documentation> <Key> <PropertyRef Name="EmployeeID" /> </Key> <Property Name="EmployeeID" Type="Int32" Nullable="false" /> <Property Name="LastName" Type="String" Nullable="false" MaxLength="20" /> <Property Name="FirstName" Type="String" Nullable="false" MaxLength="10" /> <NavigationProperty Name="Orders" Relationship="NorthwindModel.FK_Orders_Employees" FromRole="Employees" ToRole="Orders" /> </EntityType> </Schema> </edmx:ConceptualModels > <!-- SSDL content --> <edmx:StorageModels > <Schema Namespace="NorthwindModel.Store" Alias="Self" ProviderManifestToken="09.00.1399" xmlns="http://schemas.microsoft.com/ado/2006/04/edm/ssdl" > <EntityContainer Name="dbo" > <EntitySet Name="Employees" EntityType="NorthwindModel.Store.Employees" /> <AssociationSet Name="FK_Orders_Employees" Association="NorthwindModel.Store.FK_Orders_Employees" > <End Role="Employees" EntitySet="Employees" /> <End Role="Orders" EntitySet="Orders" /> </AssociationSet> </Schema> </edmx:StorageModels > <!-- C-S mapping content --> <edmx:Mappings > <Mapping Space="C-S" xmlns="urn:schemas-microsoft-com:windows:storage:mapping:CS" > <EntityContainerMapping StorageEntityContainer="dbo" CdmEntityContainer="NorthwindEntities" > <EntitySetMapping Name="Employees" > <EntityTypeMapping TypeName="IsTypeOf(NorthwindModel.Employee)" > <MappingFragment StoreEntitySet="Employees" > <ScalarProperty Name="EmployeeID" ColumnName="EmployeeID" /> <ScalarProperty Name="LastName" ColumnName="LastName" /> <ScalarProperty Name="FirstName" ColumnName="FirstName" /> </MappingFragment> </EntityTypeMapping> </EntitySetMapping> <AssociationSetMapping Name="FK_Orders_Employees" TypeName="NorthwindModel.FK_Orders_Employees" StoreEntitySet="Orders" > <EndProperty Name="Employees" > <ScalarProperty Name="EmployeeID" ColumnName="EmployeeID" /> </EndProperty> <EndProperty Name="Orders" > <ScalarProperty Name="OrderID" ColumnName="OrderID" /> </EndProperty> <Condition ColumnName="EmployeeID" IsNull="false" /> </AssociationSetMapping> </EntityContainerMapping> </Mapping> </edmx:Mappings > </edmx:Runtime> </edmx:Edmx>
[/code]
You do not have to modify this XML file manually. The Visual EDM
designer and the Mapping Details and Model Browser windows will combine
these 3 parts together and give you a nice visual representation of the
whole Entity Data Model.
When you build your project, MSBuild will extract the CSDL/SSDL/MSL
content from the EDMX
file and places these 3 seperate
XML files in your project output directory.
Model browser
![]() | The Model Browser window can be used to visualize the conceptual model and storage model in a well-organized tree hierarchy. Conceptual Model Entity Types : Employee Associations : FK_Orders_Employees Entity Container Entity Sets : Employees Association Sets Function Imports Storage Model Tables / Views : Employees Stored Procedures Constraints |
Mapping
details
The EDM designer has also a nice Mapping Detailswindow. It consists of 2 views.
Map Entity to Tables / View
This view shows all fields in the database and the correspondingproperties in the entity. It can be used to view and edit mappings in
the Entity Data Model.
![](http://www.scip.be/ImagesScreenshots/ArticleEF%20-%20Mapping%20Details.png)
Map Entity to Functions
This view can be used to select a specialized stored procedure toinsert, update or delete an instance of the entity.
![](http://www.scip.be/ImagesScreenshots/ArticleEF%20-%20Mapping%20Details%20Functions.png)
Generated
entity classes
In addition to this XML schemafile, the wizard has also generated entity classes.
Let's take a
closer look at these classes in the .Designer.cs
file
and compare them with the LINQ to SQL classes.
1) LINQ to SQL class vs EDM EntityObject class
// LINQ to SQL [Table(Name="dbo.Employees" )] public partial class Employee : INotifyPropertyChanging, INotifyPropertyChanged
[/code]
An EDM class uses different attributes and it is always inherited
from EntityObject
or ComplexObject.
The
EntityObject class provides change tracking and relationship
management. Of course this class also inherits from the
INotifyPropertyChanging and INotifyPropertyChanged interfaces so all
entities support two-way binding.
// 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 : global ::System.Data.Objects.DataClasses.EntityObject
[/code]
2) LINQ to SQL entity constructor vs. EDM Create
method
// LINQ to SQL public Employee() { this ._Employees = new EntitySet<Employee>(new Action <Employee>(this .attach_Employees), new Action <Employee>(this .detach_Employees)); this ._EmployeeTerritories = new EntitySet<EmployeeTerritory>(new Action <EmployeeTerritory>(this .attach_EmployeeTerritories), new Action <EmployeeTerritory>(this .detach_EmployeeTerritories)); this ._Orders = new EntitySet<Order>(new Action <Order>(this .attach_Orders), new Action <Order>(this .detach_Orders)); this ._Employee1 = default (EntityRef<Employee>); OnCreated(); }
[/code]
EDM does not generate a constructor like LINQ to SQL does. Instead it
creates a factory method with input parameters for all required (not
nullable) properties.
// Entity Data Model public static Employee CreateEmployee(int employeeID, string lastName, string firstName) { Employee employee = new Employee (); employee.EmployeeID = employeeID; employee.LastName = lastName; employee.FirstName = firstName; return employee; }
[/code]
3) LINQ to SQL vs. EDM : entity property
// LINQ to SQL [Column(Storage="_EmployeeID" , AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY" , IsPrimaryKey=true , IsDbGenerated=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 .OnEmployeeIDChanged(); } } }
[/code]
The attributes of a public property are different in EDM but the get
and set accessors are almost the same.
// Entity Data Model [global ::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute (EntityKeyProperty=true , IsNullable=false )] [global ::System.Runtime.Serialization.DataMemberAttribute ()] public int EmployeeID { get { return this ._EmployeeID; } set { this .OnEmployeeIDChanging(value ); this .ReportPropertyChanging("EmployeeID" ); this ._EmployeeID = global ::System.Data.Objects.DataClasses.StructuralObject .SetValidValue(value ); this .ReportPropertyChanged("EmployeeID" ); this .OnEmployeeIDChanged(); } }
[/code]
4) LINQ to SQL Table vs. EDM ObjectQuery
// LINQ to SQL public System.Data.Linq.Table<Employee> Employees { get { return this .GetTable<Employee>(); } }
[/code]
In LINQ to SQL the GetTable method is called to return a collection
of entities. In EDM an Entity SQL query will be executed through a
Object Services component which returns an EntitySet of EntityTypes.
// Entity Data Model [global ::System.ComponentModel.BrowsableAttribute (false )] public global ::System.Data.Objects.ObjectQuery <Employee > Employees { get { if ((this ._Employees == null )) { this ._Employees = base .CreateQuery<Employee >("[Employees]" ); } return this ._Employees; } } private global ::System.Data.Objects.ObjectQuery <Employee > _Employees;
[/code]
5) LINQ to SQL DataContext vs. EDM ObjectContext
// LINQ to SQL [System.Data.Linq.Mapping.DatabaseAttribute(Name="Northwind" )] public partial class NorthwindDataContext : System.Data.Linq.DataContext
[/code]
EDM has an equivalent of the LINQ to SQL DataContext, namely an ObjectContext
.
The ObjectContext
class is the primary class for
interacting with data as objects that are instances of entity types
defined in the Entity Data Model. An ObjectContext can be used to make a
connection to the database, to retrieve data, to store the persistent
objects and to perform insert, update and delete actions on the
database.
// Entity Data Model public partial class NorthwindEntities : global ::System.Data.Objects.ObjectContext
[/code]
The connection string of an ObjectContext refers to the metadata
(CSDL/SSDL/MSL files) and the data source (database connection string).
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""
[/code]
Documentation
EntityTypes, Associations and Properties in the Entity Data Modelhave a Documentation
property. This is new compared to
LINQ to SQL.
![](http://www.scip.be/ImagesScreenshots/ArticleEF%20-%20Documentation.png)
These documentation properties will update the XML comment of the
generated partial entity classes. This is great because it can be used
to generate code documentation help files with SandCastle.
/// <summary> /// Employee entity which corresponds with the Northwind.Employees table /// </summary> /// <KeyProperties> /// EmployeeID /// </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.EntityObject
[/code]
Entity SQL
Entity SQL (E-SQL) is a text-based, collection-oriented andlate-bound query language which is influenced by Transact-SQL. It
allows you to create queries on the Entity Data Model. Entity SQL
statements can be executed with both Object Services components and
Entity Client components. It is quite elaborated and some things can
become complicated. In this first article I will only be focusing on
the various query techniques. So only simple queries without complex
conditions, without associations and without aggregates will be
demonstrated.
ObjectQuery<T> queries which
return entity types
This example will show how to execute an Entity SQL query thatreturns a collection of instances of one entity type.
1) First create a Northwind ObjectContext
instance.
2) The Entity SQL statements itself are string expressions. In most
cases they will be composed as SELECT-FROM
query
expressions. Use the VALUE
keyword
in
the SELECT clause to indicate that the entity should be flattened to a
row.
3) We will use some Object Services components to execute the query.
So call the CreateQuery<T>()
factory method of
the ObjectContext
. This will create an ObjectQuery
object which represents a query against the store. This query will be
formulated through the Entity SQL statement.
4) The Entity Framework uses deferred loading. So the SQL statement is executed at the point your code
explicitly needs the data.
In this case the query will be
executed in the first loop of the ForEach iteration.
NorthwindEntities context = new NorthwindEntities (); var sql = "SELECT VALUE emp FROM NorthwindEntities.Employees AS emp" ; var query = context.CreateQuery<Employee >(sql); foreach (var emp in query) Console .WriteLine("{0} {1} {2} {3}" , emp.EmployeeID, emp.FirstName, emp.LastName, emp.Country);
[/code]
Instead of using the factory method CreateQuery<T>() you can
also create an ObjectQuery
object yourself. The second
parameter is the object context.
NorthwindEntities context = new NorthwindEntities (); var sql = "NorthwindEntities.Employees" ; ObjectQuery <Employee > query = new ObjectQuery <Employee >(sql, context); foreach (var emp in query) Console .WriteLine("{0} {1} {2} {3}" , emp.EmployeeID, emp.FirstName, emp.LastName, emp.Country);
[/code]
Let's add a WHERE
clause :
var sql = "SELECT VALUE emp FROM NorthwindEntities.Employees AS emp " + "WHERE emp.Country = 'USA'" ; var query = context.CreateQuery<Employee >(sql);
[/code]
ObjectQuery<T>
queries with parameters
Parameters are variables that are defined outside Entity SQL but inthe query statement you have to define these parameter names with the at
(@) symbol as a prefix. Parameters have to be created as ObjectParameter
objects. They can be added to the ObjectQuery
instance.
So let us add a Country parameter :
var sql = "SELECT VALUE emp FROM NorthwindEntities.Employees AS emp " + "WHERE emp.Country = @country" ; var query = context.CreateQuery<Employee >(sql); query.Parameters.Add(new ObjectParameter ("country" , "USA" ));
[/code]
We can also do the same without using the CreateQuery<T>()
factory method.
var sql = "SELECT VALUE emp FROM NorthwindEntities.Employees AS emp " + "WHERE emp.Country = @country" ; ObjectQuery <Employee > query = new ObjectQuery <Employee >(sql, context); query.Parameters.Add(new ObjectParameter ("country" , "USA" ));
[/code]
ObjectParameter
objects can also be passed to the CreateQuery<T>()
method.
var sql = "SELECT VALUE emp FROM NorthwindEntities.Employees AS emp " + "WHERE emp.Country = @country" ; var query = context.CreateQuery<Employee >(sql, new ObjectParameter ("country" , "USA" ));
[/code]
A third alternative is to use the Where
extension
method. Use the keyword it
to refer to the current
query statement.
var sql = "SELECT VALUE emp FROM NorthwindEntities.Employees AS emp" ; var query = context.CreateQuery<Employee >(sql) .Where("it.Country = @country" , new ObjectParameter ("country" , "USA" ));
[/code]
ObjectQuery<T> queries
which return primitive types
It is also possible to return a collection of primitive types instead ofentity types. Therefore you have to make sure that the SELECT clause
only returns 1 value. You also have to specify the primitive type in the
CreateQuery
method.
var sql = "SELECT VALUE emp.EmployeeID FROM NorthwindEntities.Employees AS emp " + "WHERE emp.Country = @country" ; var query = context.CreateQuery<int >(sql, new ObjectParameter ("Country" , "USA" )); foreach (var id in query) Console .WriteLine("{0}" , id.ToString());
[/code]
var sql = "SELECT VALUE emp.Country FROM NorthwindEntities.Employees AS emp " + "WHERE emp.EmployeeID = @id" ; var query = context.CreateQuery<string >(sql, new ObjectParameter ("id" , 1)); Console .WriteLine(query.First());
[/code]
Besides using Entity SQL, you can also use a query builder method to
achieve the same result. Entity SQL provides a SelectValue
method which will skip the implicit row construction. Only one item may
be specified in a select value clause.
string country = context.Employees.SelectValue<string >("it.Country" , new ObjectParameter ("id" , 1)).First(); Console .WriteLine(country);
[/code]
ObjectQuery<T> queries
which return anonymous types
It is also possible to do some data shaping and to createObjectQuery<T> queries which return anonymous types. Just change
the SELECT clause and use the DbDataRecord
class in the
CreateQuery
method. The DBDataRecord class was
introduced in .NET 1.0 and it provides data binding support for any kind
of enumeration.
var sql = "SELECT emp.LastName, emp.FirstName " + "FROM NorthwindEntities.Employees AS emp " ; var query = context.CreateQuery<DbDataRecord >(sql); foreach (var emp in query) Console .WriteLine("{0} {1}" , emp[0], emp[1]);
[/code]
var sql = "SELECT emp.LastName AS FamilyName, emp.FirstName " + "FROM NorthwindEntities.Employees AS emp " ; var query = context.CreateQuery<DbDataRecord >(sql); foreach (var emp in query) Console .WriteLine("{0} {1}" , emp["FamilyName" ], emp["FirstName" ]);
[/code]
EntityCommand queries which
return entity types
Entity SQL can also be executed through EntityClient components. Thisneeds more plumbing but in some cases it can have advantages.
1) First create an EntityConnection
. I have re-used
the connectionstring of my Northwind data context. Open this connection.
2) Create an EntityCommand
object and pass the
Entity SQL statement and connection to it.
3) Create a DbDataReader
and loop through the
results of the command.
NorthwindEntities context = new NorthwindEntities (); EntityConnection conn = new EntityConnection (context.Connection.ConnectionString); conn.Open(); var 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["LastName" ], reader["FirstName" ], reader["Country" ]); }
[/code]
When using a data reader with sequential access you always have to be
careful when accessing data. This should be done in sequential order !
e.g. When you change the order of the members/properties, you will
get an InvalidOperationException
. "Attempt to read
from column ordinal '0' is not valid. With
CommandBehavior.SequentialAccess, you may only read from column ordinal
'2' or greater.
"
Update 20/10/2008
: In Beta 3 all members/properties were
ordered according the order in the database. In SP1 all properties are
organized by alphabetical order. So in this example you should read
Country, EmployeeID, FirstName and LastName.
EntityCommand queries which
return anonymous types
Data shaping with anonymous types can be done with just the sametechniques :
EntityConnection conn = new EntityConnection (context.Connection.ConnectionString); conn.Open(); var sql = "SELECT 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["FirstName" ]); }
[/code]
EntityCommand
queries with parameters
Adding parameters can also be done easily. Add parameter names with@-prefixes in the Entity SQL string and create EntityParameter
objects. Add them to the EntityCommand
object.
EntityConnection conn = new EntityConnection (context.Connection.ConnectionString); conn.Open(); var sql = "SELECT VALUE emp FROM NorthwindEntities.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(CommandBehavior .SequentialAccess); while (reader.Read()) { Console .WriteLine("{0} {1} {2} {3}" , reader["EmployeeID" ], reader["LastName" ], reader["FirstName" ], reader["Country" ]); }
[/code]
LINQ to Entities
LINQ was introduced in .NET 3.5 and I am still excited about this technology.I prefer querying with LINQ to
Entities above Entity SQL. LINQ queries do have some restrictions but
they are easier, more natural and in addition they are strong-typed so
IntelliSense can help you creating queries.
LINQ to Entities is almost the same as LINQ to Objects and LINQ to
SQL. So I will just show 2 basic LINQ to Entities queries. Other
examples of LINQ queries can be found in several articles
on my website.
LINQ queries with
parameters
NorthwindEntities context = new NorthwindEntities (); string country = "USA" ; var query = from e in context.Employees where e.Country == country select e; foreach (var emp in query) Console .WriteLine("{0} {1} {2} {3}" , emp.EmployeeID, emp.FirstName, emp.LastName, emp.Country);
[/code]
LINQ
queries which return anonymous types
NorthwindEntities context = new NorthwindEntities (); var query = from e in context.Employees select new { e.LastName, e.FirstName }; foreach (var emp in query) Console .WriteLine("{0} {1}" , emp.LastName, emp.FirstName);
[/code]
I hope that this walkthrough provides a good overview of the Entity
Data Model and the various querying techniques that the Entity
Framework provides. In the next parts of my series about the ADO.NET
Entity Framework I will try to cover more advanced Entity SQL query
techniques, viewing SQL statements, eager loading, change tracking,
concurrency, ... So stay tuned. If you have any remarks or suggestions,
please let me know.
相关文章推荐
- ADO.Net Entity Framework Linq To Entities 语法功能汇编
- ADO.Net Entity Framework Linq To Entities 语法功能汇编
- ADO.Net Entity Framework Linq To Entities 语法功能汇编
- ADO.NET Entity Framework 学习初级篇3-- LINQ TO Entities
- ADO.NET Entity Framework 学习初级篇3-- LINQ TO Entities
- EF Provider for Access/ODBC 以及ADO.Net Entity Framework 与Linq to SQL的比较和适用场景
- LINQ to SQL(LINQ2SQL) vs. ADO.NET Entity Framework
- LINQ to SQL(LINQ2SQL) vs. ADO.NET Entity Framework
- ADO.NET Entity Framework beta 3 和Linq to SQL 在缓存处理上的不同
- LINQ to SQL(LINQ2SQL) vs. ADO.NET Entity Framework
- linq to sql =>; ADO.NET Entity Framework
- LINQ to SQL和ADO.NET Entity Framework之间的抉择
- Entity Framework (EF)/Linq To entity/ ESQL(entity sql)区别 ADO.NET Entity Framework:来自微软官方的ORM框架
- [新手入门]快速学习 ADO.NET Entity Framework系列文章 #3 -- LINQ-to-SQL、EntitySQL、查询产生器方法(Query builder)三种语法
- LINQ to SQL(LINQ2SQL) vs. ADO.NET Entity Framework(ADOEF)-ccBoy版
- ADO.NET Entity framework 与 LINQ TO SQL 中的功能的一些差别(一)
- Comparision Linq toSQL with ADO.net Entity Framework
- EF Provider for Access/ODBC 以及ADO.Net Entity Framework 与Linq to SQL的比较和适用场景:
- 转:LINQ to SQL(LINQ2SQL) vs. ADO.NET Entity Framework(ADOEF)-ccBoy版
- [转]LINQ to SQL(LINQ2SQL) vs. ADO.NET Entity Framework