New information has been added to this article since publication.
Refer to the Editor's Update below.

Data Points

ADO.NET Entity Framework Overview

John Papa

Code download available at: DataPoints2007_07.exe(1590 KB)

Contents

Entity Framework Components
Entity Data Model
Generating an Entity Data Model
Dissecting the CSDL
Mapping to the Store
Defining Inheritance
Mapping across Multiple Tables
Using EntityClient
Using Object Services
Using LINQ to Entities
Wrapping Up

[Editor's Update - 6/19/2007: The ADO.NET Entity Framework and Tools will ship during the first half of 2008 as an update to the Visual Studio 2008 release.]

ADO.NET in the next release of Visual Studio® code-named "Orcas" features the new Entity Framework. It allows developers to focus on data through an object model instead of through a logical/relational data model. The Entity Framework helps abstract the logical data schema into a conceptual model and allows for multiple ways to interact with the conceptual model through Object Services and a new data provider called EntityClient. This month’s column discusses what the Entity Framework is, how it fits into an application, and how it can be designed and programmed against.

The Entity Framework abstracts the logical database structure using a conceptual layer, a mapping layer, and a logical layer. In this column, I review the purpose of each of these layers. I also introduce EntityClient and a new language, Entity SQL, that can interact with the conceptual layer’s Entity Data Model (EDM).

An alternative to EntityClient is Object Services. Specifically, Object Services in the Entity Framework can help alleviate the amount of data-access code developers need to write. I also discuss and demonstrate how to use Object Services with Entity SQL and with LINQ to Entities to interact with and retrieve conceptual entities from the EDM.

Note that all of the examples in this article work with ADO.NET and the Entity Framework as they exist in Beta 1 of "Orcas."

Entity Framework Components

The Entity Framework allows developers to write less data-access code, reduces maintenance, abstracts the structure of the data into a more business-friendly (and less normalized) manner, and facilitates the persistence of data. When used with LINQ to Entities (to be discussed later), it can also help to reduce the number of compile time errors since it generates strongly typed classes from the conceptual model.

The Entity Framework generates a conceptual model that developers can write code against. This model can be interacted with directly using a new data provider called EntityClient and a new language (similar to T-SQL) called Entity SQL. EntityClient has a similar model to the familiar ADO.NET objects, using EntityConnection and EntityCommand objects to return a DbDataReader. Another option for developers is to employ Object Services using either an ObjectQuery object with Entity SQL or using LINQ to Entities. Object Services allows developers to take advantage of the conceptual model’s generated classes, which offer such features as strongly typed objects and persistence (see Figure 1).

Figure 1 Overview of the Entity Framework

Figure 1** Overview of the Entity Framework **

These data-access techniques let a developer interact with the conceptual entities of the EDM. The layers of the EDM exist as XML files; at this time the EDM can be generated using a command line tool (EDMGEN.EXE), manually, or with a wizard in Visual Studio.

Entity Data Model

The core of the Entity Framework is in its models. The Entity Framework supports a logical store model that represents the relational schema from a database. A relational database often stores data differently than an application uses the data. This typically forces developers to retrieve the data in the same structure as the database contains it. Developers often then feed the data into business entities that are more suited for handling business rules. In this example, the schema from the relational database is represented in a logical model and the business entities represent the conceptual model. The Entity Framework bridges this gap between the models using a mapping layer. Thus there are three layers active in the Entity Framework’s model:

  • Conceptual layer
  • Mapping layer
  • Logical layer

These three layers allow data to be mapped from a relational database to a more object-oriented business model. The Entity Framework provides the means to define these layers using XML files. It also generates a series of classes based on the schema of the conceptual model. You can program against these classes directly to interact with the data. This provides a level of abstraction so developers can program against the conceptual model instead of the relational model. The Entity Framework maps all commands coded against the conceptual model into the logical model (see Figure 2).

Figure 2 Designing the Entity Data Model

Figure 2** Designing the Entity Data Model **(Click the image for a larger view)

The conceptual model is defined in an XML file using the Conceptual Schema Definition Language (CSDL). The CSDL defines the entities and the relationships as the application’s business layer knows them. The logical model, which represents the database schema, is defined in an XML file using the Store Schema Definition Language (SSDL). For example, you might have an entity in a conceptual model that actually derives its data from multiple tables in a database. The conceptual model and the logical model can associate entities one-to-one. However, the power of the EDM is that it does not have to link them one-to-one. The mapping layer, which is defined using the Mapping Schema Language (MSL), maps the other two layers between each other. This mapping is what allows developers to code against the conceptual model and have those instructions mapped into the logical model.

Generating an Entity Data Model

You can generate an EDM using a database as a starting point. You can then modify the XML manually (or possibly using a modeling tool that may be available in a future release of Visual Studio). When you add an ADO.NET EDM to your project, the wizard walks you through the process of creating the EDM.

After choosing to generate the EDM from the sample Northwind database that comes with "Orcas," you are prompted with a list of objects that it can model, as shown in Figure 3. I chose to bring all the tables into the model so the wizard generates CSDL, SSDL, and MSL files for all of the tables in Northwind. Of course, this is a pure one-to-one table-to-entity mapping. I can adjust this mapping to suit my business needs by combining entities or perhaps through inheritance.

Figure 3 The EDM Wizard

Figure 3** The EDM Wizard **(Click the image for a larger view)

The wizard also generates a series of classes from the CSDL that represent the domain model. Some of these classes are shown in Figure 4 through the Class View window. Due to the one-to-one mapping with which I started, there is a class for every table. The EDM wizard picked up on the relationship between Customers and Orders in the database and created a corresponding association for them in the conceptual model. Therefore, the Customers class contains a navigation property, called Orders, that allows developers to navigate from a Customers instance down to any associated Orders instances for a customer.

Figure 4 Classes

Figure 4** Classes **

Dissecting the CSDL

The metadata residing within the CSDL file contains a list of entities, represented by the EntityType element, and of relations, represented by the Association element, which is an AssociationType (note that this is an inconsistency in the naming scheme within Beta 1). A fragment of the CSDL file I generated earlier is shown in Figure 5. The entities contain a list of scalar properties that define the entity. The Key attribute indicates which properties are the key for the entity. Compound keys are indicated by separating each property name with a space. Entities can also contain a special type of property called a NavigationProperty. This defines how to navigate from one entity following the associations to another entity.

Figure 5 EntityType Definition in CSDL

<EntityType Name=”Customers” Key=”CustomerID”>
    <Property Name=”CustomerID” Type=”String” Nullable=”false” 
MaxLength=”4000” FixedLength=”true” />
    <Property Name=”CompanyName” Type=”String” Nullable=”false” 
MaxLength=”4000” />
    <Property Name=”ContactName” Type=”String” MaxLength=”4000” />
    <Property Name=”ContactTitle” Type=”String” MaxLength=”4000” />
    <Property Name=”Address” Type=”String” MaxLength=”4000” />
    <Property Name=”City” Type=”String” MaxLength=”4000” />
    <Property Name=”Region” Type=”String” MaxLength=”4000” />
    <Property Name=”PostalCode” Type=”String” MaxLength=”4000” />
    <Property Name=”Country” Type=”String” MaxLength=”4000” />
    <Property Name=”Phone” Type=”String” MaxLength=”4000” />
    <Property Name=”Fax” Type=”String” MaxLength=”4000” />
    <NavigationProperty Name=”Orders” 
Relationship=”NorthwindModel.FK_Orders_Customers” 
FromRole=”Customers” ToRole=”Orders” />
  </EntityType>

The AssociationType between the Customer and its Orders is defined in this CSDL fragment:

  <Association Name=”FK_Orders_Customers”>
     <End Role=”Customers” Type=
         ”NorthwindModel.Customers”   
         Multiplicity=”0..1” />
     <End Role=”Orders” Type=
         ”NorthwindModel.Orders” Multiplicity=”*” />
  </Association>

The End elements of the AssociationType indicate the participants of the association. In this example, a Customers entity is associated with an Orders entity. A Customers entity can also be related to any number of Orders entities, as defined by the multiplicity.

While the EntityType and AssociationType elements define the types of domain entities and relationships, the EntitySet and AssociationSet elements define the scope of them. All "sets" that should be logically grouped together are contained within an EntityContainer element. (For the full CSDL, see the NorthwindEntities.csdl file in the accompanying download.)

The following CSDL fragment shows the EntityContainer and some of its contents:

<EntityContainer Name=”NorthwindEntities”>
    <EntitySet Name=”Customers” 
        EntityType=”NorthwindModel.Customers” />
    <EntitySet Name=”Orders” 
        EntityType=”NorthwindModel.Orders” />
    <AssociationSet Name=”FK_Orders_Customers” 
            Association=”NorthwindModel.FK_Orders_Customers”>
        <End Role=”Customers” EntitySet=”Customers” />
        <End Role=”Orders” EntitySet=”Orders” />
    </AssociationSet>

</EntityContainer>

This fragment shows the EntitySets for the EntityTypes Customers and Orders. The AssociationSet FK_Orders_Customers is also declared here. This fragment is what defines the entities Customers and Orders as well as the relationship between them.

Mapping to the Store

The SSDL file defines the structure of the relational data in the database. It also uses the EntityType and AssociationType XML elements, in this case to declare the structures of tables and foreign keys that exist in the database, respectively. The SSDL file’s namespace is set based on the name of the database used in the EDM while its EntityContainer element is named after the database schema. The EntityContainer contains a series of EntitySet and AssociationSet elements, which declare the instances of the tables and relationships represented by the EntityType and AssociationType. For every EntitySet in the SSDL file there is a single corresponding table in the database.

If you generate an EDM from a database and immediately open the CSDL and SSDL files without making modifications to them, you will find that they are strikingly similar. This is because the models are generated directly from the database so the conceptual model is mapped directly to the logical store. The MSL file contains the direct map from the CSDL to the SSDL. All queries written against the EDM are translated into generated SQL commands. The Entity Framework also supports using stored procedures instead of generated SQL queries.

An EntityContainerMapping element is used to map a model (the CSDL) to the store (the SSDL). The attribute StorageEntityContainer indicates the name of the EntityContainer in the store while the EdmEntityContainer attribute indicates the corresponding EntityContainer in the model. Mapping a model’s EntitySet to a store’s EntitySet requires an EntitySetMapping element. The Name attribute defines the name of the EntitySet in the model while the TableName attribute defines the name of the corresponding EntitySet in the store. Each property in the model is mapped to the store through a ScalarProperty element. Figure 6 shows an MSL fragment.

Figure 6 Mapping the Inherited Entity in the MSL

<cs:EntitySetMapping cs:Name=”Products”>
  <cs:EntityTypeMapping cs:TypeName=”NorthwindModel.Products”>
    <cs:TableMappingFragment cs:TableName=”Products”>
      <cs:ScalarProperty cs:Name=”ProductID” cs:ColumnName=”ProductID” />
      <cs:ScalarProperty cs:Name=”ProductName” 
          cs:ColumnName=”ProductName” />
      <cs:ScalarProperty cs:Name=”QuantityPerUnit” 
          cs:ColumnName=”QuantityPerUnit” />
      <cs:ScalarProperty cs:Name=”UnitPrice” cs:ColumnName=”UnitPrice” />
      <cs:ScalarProperty cs:Name=”UnitsInStock” 
          cs:ColumnName=”UnitsInStock” />
      <cs:ScalarProperty cs:Name=”UnitsOnOrder” 
          cs:ColumnName=”UnitsOnOrder” />
      <cs:ScalarProperty cs:Name=”ReorderLevel” 
          cs:ColumnName=”ReorderLevel” />
      <!--<cs:ScalarProperty cs:Name=”Discontinued” 
          cs:ColumnName=”Discontinued” />-->
      <cs:Condition cs:ColumnName=”Discontinued” cs:Value=”0”/>
    </cs:TableMappingFragment>
  </cs:EntityTypeMapping>
<!--</cs:EntitySetMapping>
<cs:EntitySetMapping cs:Name=”DiscontinuedProducts”>-->
  <cs:EntityTypeMapping cs:TypeName=
        ”NorthwindModel.DiscontinuedProducts”>
    <cs:TableMappingFragment cs:TableName=”Products”>
      <cs:ScalarProperty cs:Name=”ProductID” cs:ColumnName=”ProductID” />
      <cs:ScalarProperty cs:Name=”ProductName” 
          cs:ColumnName=”ProductName” />
      <cs:ScalarProperty cs:Name=”QuantityPerUnit” 
          cs:ColumnName=”QuantityPerUnit” />
      <cs:ScalarProperty cs:Name=”UnitPrice” cs:ColumnName=”UnitPrice” />
      <cs:ScalarProperty cs:Name=”UnitsInStock” 
          cs:ColumnName=”UnitsInStock” />
      <cs:ScalarProperty cs:Name=”UnitsOnOrder” 
          cs:ColumnName=”UnitsOnOrder” />
      <cs:ScalarProperty cs:Name=”ReorderLevel” 
          cs:ColumnName=”ReorderLevel” />
      <cs:Condition cs:ColumnName=”Discontinued” cs:Value=”1”/>
    </cs:TableMappingFragment>
  </cs:EntityTypeMapping>
</cs:EntitySetMapping>

Defining Inheritance

The EDM also supports models that are not purely one-to-one with the database. For example, using the Northwind database, you can create a class called DiscontinuedProducts, which inherits all properties from the Products class but only contains products whose Discontinued column is 1. (Note that the DiscontinuedProducts class could also add additional properties.) This is a simplistic inheritance scenario, but it demonstrates how to implement inheritance using the EDM.

The first step in creating the DiscontinuedProducts class in the conceptual model is to open the CSDL file and create a new EntityType, name it DiscontinuedProducts, and set its BaseType attribute to NorthwindModel.Products (the schema and base EntityType name). The derived EntityType inherits the properties of the Products EntityType including its Keys. Therefore, I do not specify the Key attribute or the properties for the new derived EntityType. I also comment out the Discontinued property from the Products EntityType. The additional code needed to do all of this in the CSDL file looks like this:

<EntityType Name=”DiscontinuedProducts” 
    BaseType=”NorthwindModel.Products”/>

The next step in this process is to open the MSL file and find the Products EntitySetMapping element and remove its TypeName and TableName attributes. These will now be set for each specific EntityType. Then create an EntityTypeMapping child element and set its TypeName to NorthwindModel.Products. For each EntityType that inherits from a base EntityType, the EntitySetMapping must include an EntityTypeMapping element. Create a child of the EntityTypeMapping element called TableMappingFragment and set its TableName attribute to Products. Basically, these steps move the mapping from the EntitySetMapping element down to a more granular level.

Comment out the Discontinued property mapping and add a Condition element that indicates that only records with Discontinued equal to 0 will be included. Copy the entire EntityTypeMapping XML fragment, change the Name attribute to DiscontinuedProducts, and change the condition to a value of 1. The new fragment of the MSL file is shown in Figure 6.

Mapping across Multiple Tables

Another way that the EDM can vary from the pure one-to-one model to store mapping is to map a single entity in the model to multiple tables in the store. The Contacts table and the ContactNameSplit table in the sample Northwind database have a one-to-one relationship between them and can be combined into a single entity in the model. For this example, I will create an entity in the model that includes all columns from the Contacts table and the Title and Name columns from the ContactNameSplit table.

The first change is to modify the Contacts EntityType in the CSDL file to include two additional properties: Name and Title.

The next set of changes is a bit more verbose. These two new properties in the model must now be mapped to the store with the MSL file. The EntitySetMapping element for the Contacts EntitySet must be changed to represent a mapping to multiple tables. For this example, I modified the existing EntitySetMapping tag for the Contacts EntitySet by removing the TableName and TypeName attributes. These attributes are only declared in the EntitySetMapping element if the EntitySet in the model maps one-to-one with an EntitySet in the store.

Since the mapping from the model EntitySet to the store EntitySet for Contacts has been removed, a replacement must be created. This replacement is a child element called EntityTypeMapping. Two of these must be created—one each to represent the Contacts and the ContactNameSplit from the store. The EntityTypeMapping elements define the TypeName attribute for each of the EntitySets.

Inside each of the EntityTypeMapping elements is a child element called TableMappingFragment. This element contains the TableName attribute, which corresponds to the store’s EntitySet. The TableMappingFragment is where all of the ScalarProperty elements are defined that map the model’s properties to the store. Figure 7 shows the revised Contacts EntitySetMapping that now maps the Contacts and ContactSplitName tables from the store into a single EntitySet in the model.

Figure 7 Combining Tables into an Entity

<cs:EntitySetMapping cs:Name=”Contacts”>
  <cs:EntityTypeMapping cs:TypeName=”NorthwindModel.Contacts”>
    <cs:TableMappingFragment cs:TableName=”Contacts”>
      <cs:ScalarProperty cs:Name=”ContactID” 
          cs:ColumnName=”ContactID” />
      <cs:ScalarProperty cs:Name=”ContactType” 
          cs:ColumnName=”ContactType” />
      <cs:ScalarProperty cs:Name=”CompanyName” 
          cs:ColumnName=”CompanyName” />
      <cs:ScalarProperty cs:Name=”ContactName” 
          cs:ColumnName=”ContactName” />
      <cs:ScalarProperty cs:Name=”ContactTitle” 
          cs:ColumnName=”ContactTitle” />
      <cs:ScalarProperty cs:Name=”Address” cs:ColumnName=”Address” />
      <cs:ScalarProperty cs:Name=”City” cs:ColumnName=”City” />
      <cs:ScalarProperty cs:Name=”Region” cs:ColumnName=”Region” />
      <cs:ScalarProperty cs:Name=”PostalCode” 
          cs:ColumnName=”PostalCode” />
      <cs:ScalarProperty cs:Name=”Country” cs:ColumnName=”Country” />
      <cs:ScalarProperty cs:Name=”Phone” cs:ColumnName=”Phone” />
      <cs:ScalarProperty cs:Name=”Extension” 
          cs:ColumnName=”Extension” />
      <cs:ScalarProperty cs:Name=”Fax” cs:ColumnName=”Fax” />
      <cs:ScalarProperty cs:Name=”PhotoPath” 
          cs:ColumnName=”PhotoPath” />
    </cs:TableMappingFragment>
  </cs:EntityTypeMapping>
  <cs:EntityTypeMapping cs:TypeName=”ContactNameSplit”>
    <cs:TableMappingFragment cs:TableName=”ContactNameSplit”>
      <cs:ScalarProperty cs:Name=”ContactID” cs:ColumnName=”ID” />
      <cs:ScalarProperty cs:Name=”Name” cs:ColumnName=”Name” />
      <cs:ScalarProperty cs:Name=”Title” cs:ColumnName=”Title” />
    </cs:TableMappingFragment>
  </cs:EntityTypeMapping>

Using EntityClient

Accessing the Entity Framework’s conceptual model can be done through any of three different mechanisms (see Figure 1). Here I will introduce EntityClient, the new .NET data provider.

EntityClient is abstracted from the logical store as it communicates with the conceptual model using its own text-based language called Entity SQL. All Entity SQL queries executed using EntityClient are compiled into command trees that are sent to the store. The conversion of the queries from Entity SQL through the conceptual model and down to the store are handled by the Entity Framework.

The classes in EntityClient are similar to the classes in common ADO.NET providers. For example, EntityClient queries are executed with an EntityCommand object, which requires an EntityConnection object to connect to the EDM. While EntityClient interacts with the entities in the EDM, it does not return instances of the entities but instead returns all results in a DbDataReader object. EntityClient can return a standard set of rows and columns or it can return a representation of more-complex hierarchical data through a DbDataReader.

Figure 8 shows an example of using EntityClient to connect to the conceptual model and retrieve a list of Customers from London. The EntityConnection can accept a full connection string to the conceptual layer or the name of the connection string in the App.Config file. The connection string contains a list of the metadata files (the CSDL, MSL, and SSDL files) as well as the database-specific connection string information for the store. An example of the full connection string for Figure 8 is shown here:

Figure 8 Entity Client Using Entity SQL to Get to EDM

string city = “London”;
using (EntityConnection cn = 
    new EntityConnection(“Name=NorthwindEntities”))
{
    cn.Open();
    EntityCommand cmd = cn.CreateCommand();
    cmd.CommandText = 
         “SELECT VALUE c FROM NorthwindEntities.Customers “ +
         “AS c WHERE c.City = @city”;
    cmd.Parameters.AddWithValue(“city”, city);
    DbDataReader rdr = cmd.ExecuteReader(
        CommandBehavior.SequentialAccess);
    while (rdr.Read())
        Console.WriteLine(rdr[“CompanyName”].ToString());
    rdr.Close();
}

“metadata=.\NorthwindEntities.csdl|.\NorthwindEntities.ssdl|.
\NorthwindEntities.msl;provider=System.Data.SqlClient;provider connection string=’Data Source=DDVPC01
\SQLEXPRESS;Initial Catalog=Northwind;
Integrated Security=True’”

The code in Figure 8 shows how to create an EntityConnection object and execute an EntityCommand on it. The query written with Entity SQL is referring to the Customers EntitySet in the EDM. Note that the syntax is intentionally similar to T-SQL. (If you want a good reference for the Entity SQL syntax, see the MSDN® documentation for the Beta 1 release of "Orcas.")

As shown in Figure 8, EntityParameter objects can also be added. As of Beta 1, EntityClient does not support DML queries; it is, however, being worked on for the future. Still, DML can be executed using other means, such as LINQ to Entities.

Using Object Services

Another way to interact with the data represented by the EDM is to use Object Services. Object Services provides a way to load objects and navigate any relationships defined in the EDM. As illustrated in Figure 1, Object Services uses EntityClient to get at the data. Object Services adds identity resolution, which is a manual process when using a DataSet. It also provides object persistence and change tracking through events to allow an explicit load and save. This reduces the round-trip to the server.

Object Services allows lists of objects to be returned directly—both projections and defined entities can be returned. For example, using Object Services, you could retrieve a List<Customers> as defined in the EDM. The Customers objects can be examined, the values changed, and then the data saved back to the database.

If you use projections with Object Services, the data returned will not be an updateable object. Because projections return specific properties of entities and not the entire entity, Object Services cannot save updates to the projected data back to the database. If you intend to update the data, a better option is to return the entire entity rather than using a projection.

You can use Object Services to execute queries using Entity SQL or you can write queries using LINQ to Entities. The following example demonstrates querying with Object Services and Entity SQL to retrieve a list of Customers:

string city = “London”;
ObjectQuery<Customers> query = northwindContext.CreateQuery<Customers>(
    “SELECT VALUE c FROM Customers AS c WHERE c.City = @city”,
     new ObjectParameter(“city”, city));
foreach (Customers c in query) Console.WriteLine(c.CompanyName);

In the EDM, the EntityContainer is represented by a class that inherits from ObjectContext (northwindContext in this example). The ObjectContext class implements the ObjectQuery<T> interface, allowing it to create the queries using Entity SQL or LINQ.

The CreateQuery method accepts a parameterized Entity SQL statement that defines a query that will retrieve a list of Customers entities. The actual SQL statement that hits the database is executed when ObjectQuery<Customers> is iterated through using a foreach statement.

Using LINQ to Entities

Dynamic queries can be written in Entity SQL and used with Object Services to interact with the EDM entities. But the Entity Framework can also be used with strongly typed EDM classes using LINQ to Entities. For example, in the sample just shown, querying with Object Services and Entity SQL can be modified to be executed using LINQ to Entities, like this:

string city = “London”;
var query = from c in northwindContext.Customers
            where c.City == city
            select c;
foreach (Customers c in query) Console.WriteLine(c.CompanyName);

This code sample replaces all of the text-based syntax of Entity SQL with the strongly typed LINQ syntax supported by C# 3.0. For more information on LINQ and support for it in both C# and Visual Basic®, see the June 2007 issue of MSDN Magazine at msdn.microsoft.com/msdnmag/issues/07/06.

Now recall when I created an EntityType in the EDM, called DiscontinuedProducts, that inherits from Products. The inheritance features of the EDM can be used with LINQ and Object Services to retrieve a list of discontinued products. Note that the following example does not specify where discontinued equals 1. Instead, the type for the product entity is checked against the derived EntityType DiscontinuedProducts, which in turn uses the condition I created in the mapping (MSL file) to generate an appropriate SQL statement to only retrieve discontinued products:

var query = from p in northwindContext.Products
            where p is DiscontinuedProducts
            select p;
foreach (Products p in query) Console.WriteLine(p.ProductName);

You can also write queries that take advantage of the built-in relationships in the EDM (defined by AssociationSet). For example, a list of Orders for Customers in London can be retrieved using the following LINQ query expression:

var query = from o in northwindContext.Orders
            where o.Customers.City == “London”
            select o;
foreach (Orders o in query) Console.WriteLine(o.OrderID);

This code sample starts with the Orders entity and uses its navigation property, called Customers, to be able to examine the City property. The Orders from customers not in London are filtered out entirely. Since a list of Orders entities are returned, the entities can also be modified and their changes saved to the database. Saving changes to the database can be done through the SaveChanges method.

The following example gets the list of customers in London and sets the Country property for each of them to United Kingdom. The changes are persisted to the StateManager, but they are not written to the database until the SaveChanges method is executed:

var query = from c in northwindContext.Customers
            where c.City == “London”
            select c;
foreach (Customers c in query) c.Country = “United Kingdom”;
northwindContext.SaveChanges();

You can also create a new instance of an entity and add it to the EDM using ObjectContext’s AddObject method. The following example shows how to add a new category to the Categories table in the database:

Categories newCat = new Categories();
newCat.CategoryName = “Other”;
northwindContext.AddObject(newCat);
northwindContext.SaveChanges();
int newCatID = newCat.CategoryID; 

First an instance of the Categories entity is created and its CategoryName property is set. Then the new category is added to the EDM using the AddObject method. When the SaveChanges method is invoked, a SQL statement is generated that inserts the new Category into the database and returns the CategoryID for the new row.

When entities have relationships to other entities, you may want to associate the new entity with an existing entity. For example, you can create a new Orders entity and set its Customers property to an existing Customers entity. While the Orders table in the database has a CustomerID column, the EDM represents the relationship through an object oriented approach using a Customers property to navigate to the related Customers entity:

Orders newOrder = new Orders();
newOrder.OrderDate = DateTime.Today;
Customers cust = northwindContext.Customers.Where(
    “it.CustomerID = ‘ALFKI’”).First();
newOrder.Customers = cust;
northwindContext.AddObject(newOrder);
northwindContext.SaveChanges();

Wrapping Up

The Entity Framework allows developers to focus on the data through an object model instead of the logical/relational data model. Once the EDM is designed and mapped to a relational store, the objects can be interacted with using a variety of techniques including EntityClient, ObjectServices, and LINQ.

While the traditional objects such as the DataSet, DataAdapter, DbConnection, and DbCommand are still supported in the upcoming release of ADO.NET available in Visual Studio "Orcas," the Entity Framework brings major additions that open ADO.NET to new and exciting possibilities.

Send your questions and comments for John mmdata@microsoft.com.

John Papa is a senior .NET Consultant with ASPSOFT (aspsoft.com) and a baseball fanatic who spends most of his summer nights rooting for the Yankees with his family and his faithful dog, Kadi. John, a C# MVP, has authored several books on ADO, XML, and SQL Server, and can often be found speaking at industry conferences such as VSLive or blogging at www.johnpapa.net.