ADO.NET Entity Framework & LINQ to Entities - deel 1

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

 

The Entity Framework architecture

ADO.NET Entity Framework & LINQ to Entities - deel 1_第1张图片

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 website and 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 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 .

ADO.NET Entity Framework & LINQ to Entities - deel 1_第2张图片

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.

ADO.NET Entity Framework & LINQ to Entities - deel 1_第3张图片

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

ADO.NET Entity Framework & LINQ to Entities - deel 1_第4张图片

Entity Data Model (EDM) (Beta 3)

ADO.NET Entity Framework & LINQ to Entities - deel 1_第5张图片

Entity Data Model (EDM) (SP1)

ADO.NET Entity Framework & LINQ to Entities - deel 1_第6张图片

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 : Association

ADO.NET Entity Framework & LINQ to Entities - deel 1_第7张图片

EDM : Association

ADO.NET Entity Framework & LINQ to Entities - deel 1_第8张图片

 

Names of EntityTypes and EntitySets

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.

ADO.NET Entity Framework & LINQ to Entities - deel 1_第9张图片

So change the name of the EntityType manually :

ADO.NET Entity Framework & LINQ to Entities - deel 1_第10张图片

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.

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 EDMX file 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>

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

ADO.NET Entity Framework & LINQ to Entities - deel 1_第11张图片

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 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.

ADO.NET Entity Framework & LINQ to Entities - deel 1_第12张图片

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.

ADO.NET Entity Framework & LINQ to Entities - deel 1_第13张图片

 

Generated entity classes

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

// LINQ to SQL

[Table(Name="dbo.Employees" )]
public partial class Employee : INotifyPropertyChanging, INotifyPropertyChanged

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

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();
}

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

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();
    }
  }
}

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();
    }
}

4) LINQ to SQL Table vs. EDM ObjectQuery

// LINQ to SQL
public System.Data.Linq.Table<Employee> Employees
{
  get
  {
    return this .GetTable<Employee>();
  }
}

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;

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

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

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=&quot;
Data Source=SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True;MultipleActiveResultSets=True&quot;"

 

Documentation

EntityTypes, Associations and Properties in the Entity Data Model have a Documentation property. This is new compared to LINQ to SQL.

ADO.NET Entity Framework & LINQ to Entities - deel 1_第14张图片

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

 

Entity SQL

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.

 

ObjectQuery<T> queries which return entity types

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.

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);

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);

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);

 

ObjectQuery<T> queries with parameters

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 :

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" ));

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" )); 

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" ));

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" ));

 

ObjectQuery<T> queries which return primitive types

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.

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());
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());

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);

 

ObjectQuery<T> queries which return anonymous types

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.

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]);
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" ]);

 

EntityCommand queries which return entity types

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.

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" ]);
}

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 same techniques :

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" ]);
}

 

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" ]);
}

 

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);

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);

 

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.

你可能感兴趣的:(sql,properties,query,LINQ,Primitive,associations)