PRE01: ADO.NET Entity Framework

 José A. Blakeley
Partner Architect
Microsoft Corporation
 Michael Pizzo
Principal Architect
Microsoft Corporation









ADO.NET 1.0
 Building a Data Platform
 The ADO.NET Entity Framework




























































Evolution of Data Access APIs





Getting Data from a SQL Database
Working with Data
ADO.NET and XML
Building a Data Platform
 The ADO.NET Entity Framework

Controls,
Designers,
Code-gen, etc
XmlReader
DataSet
OLTP operations,
Programmatic Processing,
Frameworks
XmlWriter
DataAdapter
DataReader
Command
Connection
Managed Provider
ADO.NET Data Provider
Data
Provider


Data
store





Connection

CreateCommand()

Command
Parameters
Parameters
Parameters
ExecuteReader()


DataReader


DataSet

Columns
Column
Constraints
Constraint
Rows
Row
Relations
Relation









DataSet
Tables
Table











DataSet
Fill() Update()

SelectCommand
InsertCommand
UpdateCommand

DeleteCommand


Mappings
Mappings
Mappings
DataAdapter

Data
store














Evolution of Data Access APIs
 ADO.NET 1.0
 Building a Data Platform





Why a Conceptual Model?
The Microsoft Entity Data Model
Entity SQL
The ADO.NET Entity Framework
Programming Data is Hard








Increase Developer Productivity




















The Need…
Applications work with a well
Defined Model
 Storage Schema Abstraction

Declarative mapping between
application and storage models
 No brittle, hard-coded mapping

SalesPerson

Manager

EmployeeID = 294272
LoginID = adam
Title = "Dev Lead"
VacationHours = 0
…
1


Reports

N

SalesPerson












SalesPerson
EmployeeID = 729742
LoginID = pete
EmployeeID
= 729742
SalesPerson
Title = "Developer"
LoginID
= pete
VacationHours
=0
Title …= "Developer"
EmployeeID
= 729742
VacationHours
=0 =…
LoginID
=ExpenseAccount
pete
Title…= "Developer"
CarLicenseNum = …
ExpenseAccount
VacationHours
=0 =…
…
… CarLicenseNum = …
…
ExpenseAccount
= true
…














Data Access in the 80s
 ADO.NET 1.0
 Building a Data Platform






Entity Designer
EntityClient
Object Services
Data Access in the 80s
 ADO.NET 1.0
 Building a Data Platform
 The ADO.NET Entity Framework





Overview
EntityClient
Object Services




















Data Access in the 80s
 ADO.NET 1.0
 Building a Data Platform
 The ADO.NET Entity Framework





Overview
Entity Designer
Object Services















Data Access in the 80s
 ADO.NET 1.0
 Building a Data Platform
 The ADO.NET Entity Framework





Overview
Entity Designer
EntityClient
























// Lambda Expressions
string[] names = { "Luis", "Mary", "Mike", "Jose" };
Display( names, s => s.Length > 3);
// Anonymous Types and object initialization
var emp = new { Name = "Mary", Company = "Microsoft",
Age = 30 };
// Extension Methods
public static class ExtensionMethods {
public static void Display<T>(this T[] names,
Func<T, bool> filter) {
foreach (T s in names) {
if (filter(s)) Console.WriteLine(s);
}
}
}
// Query Expressions
var query = from c in Customers
where c.Discount >= 3.0 && c.Discount < 4.0
select new { c.Name, Perc = c.Discount / 100.0 };
 Introduction to LINQ




LINQ to Entities
 LINQ to DataSet

Direct Mapping









Strongly typed SQL Database












Features
















 Introduction to LINQ
 LINQ to SQL





LINQ to DataSet
Flexible Mapping to Relational Data
•
•
•
•
•
•
•
•
•

Features














 Introduction to LINQ
 LINQ to SQL
 LINQ to Entities

LINQ over Disconnected Cache with Change Tracking










Typed and UnTyped

AsEnumerable()



Field<T>(columnName)

var query = from row in myDataSet.Tables["Customers"].AsEnumerable()
where row .Field<string>("City") == "London"
select new { row.Field <string> ("CustomerID"),
row.Field <string> ("ContactName") } ;

Typed DataSet

Use strongly typed accessors
var query = from customer in northwind.Customers
where customer.City == "London"
select customer;















Customizing Data Classes













Customizing Data Classes
Entity Framework Mapping Scenarios





Core Mapping Scenarios
Function Mapping
Mapping Limitations
Database Design Considerations
Advanced Mapping Techniques
































Customizing Data Classes
 Entity Framework Mapping Scenarios
 Database Design Considerations















<Schema Namespace="AdventureWorksModel" Alias="Self"
xmlns="http://schemas.microsoft.com/ado/2006/04/edm">
<EntityContainer Name="AdventureWorksEntities">
<EntitySet Name="Contacts"
EntityType="AdventureWorksModel.Contact" />
<AssociationSet Name="ManagerEmployees"
Association="AdventureWorksModel.ManagerEmployee">
<End Role="Employees" EntitySet="Contacts" />
<End Role="Manager" EntitySet="Contacts" />
</AssociationSet>
</EntityContainer>
<EntityType Name="Contact">
<Key>
<PropertyRef Name="ContactID" />
</Key>
<Property Name="ContactID" Type="Int32" Nullable="false" />
<Property Name="Title" Type="String" />
<Property Name="FirstName" Type="String" Nullable="false" />
<Property Name="LastName" Type="String" Nullable="false" />
</EntityType>
<Association Name="ManagerEmployee">
<End Role="Employees"
Type="AdventureWorksModel.Employee" Multiplicity="*" />
<End Role="Manager"
Type="AdventureWorksModel.Employee" Multiplicity="0..1" />
</Association>
</Schema>
<Schema Namespace="AdventureWorksModel.Store" Alias="Self"
Provider="System.Data.SqlClient" ProviderManifestToken="2008"
xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator"
xmlns="http://schemas.microsoft.com/ado/2006/04/edm/ssdl">
<EntityContainer Name="HumanResources">
<EntitySet Name="Contact"
EntityType="AdventureWorksModel.Store.Contact" Schema="Person" />
<AssociationSet Name="FK_Employee_Employee_ContactID"
Association= "AdventureWorksModel.Store.FK_Employee_Employee_ContactID">
<End Role="Employees" EntitySet="Employee" />
<End Role="Manager" EntitySet="Employee" />
</AssociationSet>
</EntityContainer>
<EntityType Name="Contact">
<Key>
<PropertyRef Name="ContactID" />
</Key>
<Property Name="ContactID" Type="int" Nullable="false" StoreGeneratedPattern="Identity" />
<Property Name="Title" Type="nvarchar" />
<Property Name="FirstName" Type="nvarchar" Nullable="false" />
<Property Name="LastName" Type="nvarchar" Nullable="false" />
</EntityType>
<Association Name="FK_Employee_Employee_ContactID">
<End Role="Employees" Type="AdventureWorksModel.Store.Employee" Multiplicity="*" />
<End Role="Manager" Type="AdventureWorksModel.Store.Employee" Multiplicity="0..1" />
</Association>
</Schema>
<Mapping Space="C-S" xmlns="urn:schemas-microsoft-com:windows:storage:mapping:CS">
<EntityContainerMapping StorageEntityContainer="HumanResources"
CdmEntityContainer="AdventureWorksEntities">
<EntitySetMapping Name="Contacts"
TypeName="AdventureWorksModel.Contact" StoreEntitySet="Contact">
<ScalarProperty Name="ContactID" ColumnName="ContactID" />
<ScalarProperty Name="Title" ColumnName="Title" />
<ScalarProperty Name="FirstName" ColumnName="FirstName" />
<ScalarProperty Name="MiddleName" ColumnName="MiddleName" />
<ScalarProperty Name="LastName" ColumnName="LastName" />
</EntitySetMapping>
<AssociationSetMapping Name="ManagerEmployees"
TypeName="AdventureWorksModel.ManagerEmployee" StoreEntitySet="Employee">
<EndProperty Name="Employees">
<ScalarProperty Name="ContactID" ColumnName="ContactID" />
</EndProperty>
<EndProperty Name="Manager">
<ScalarProperty Name="ContactID" ColumnName="ManagerID" />
</EndProperty>
<Condition ColumnName="ManagerID" IsNull="false" />
</AssociationSetMapping>
</EntityContainerMapping>
</Mapping>
Customizing Data Classes
 Entity Framework Mapping Scenarios
 Database Design Considerations
 Advanced Mapping Techniques




Anatomy of an .edmx file
Custom Mapping

<ComplexType Name ="FullName">
<Property Name="Title" Type="String" />
<Property Name="FirstName" Type="String" Nullable="false" />
<Property Name="MiddleName" Type="String" />
<Property Name="LastName" Type="String" Nullable="false" />
</ComplexType>

Use your ComplexType in your Entities
<EntityType Name="Contact">
<Key>
<PropertyRef Name="ContactID" />
</Key>
<Property Name="ContactID" Type="Int32" Nullable="false" />
<Property Name="Name" Type="Self.FullName" Nullable="false"/>
<!-- … -->
</EntityType>

Map the Complex Type in your MSL
<EntitySetMapping Name="Contacts" TypeName="AdventureWorksModel.Contact"
StoreEntitySet="Contact">
<ScalarProperty Name="ContactID" ColumnName="ContactID" />
<ComplexProperty Name="Name">
<ScalarProperty Name="Title" ColumnName="Title" />
<ScalarProperty Name="FirstName" ColumnName="FirstName" />
<ScalarProperty Name="LastName" ColumnName="LastName" />
</ComplexProperty>
</EntitySetMapping>
Entity Framework Mapping Scenarios
 Database Design Considerations
 Customizing Data Classes
 Advanced Mapping Techniques




Anatomy of an .edmx file
Complex Types
Customize Conceptual Definition







Customize Mapping Definition



























ADO.NET and SQL Server
 Futures
 Summary: ADO.NET A to Z






















































Data Access Across Tiers












Futures










 Simple programming model
 Strongly typed
CREATE TYPE myTableType AS TABLE
(id INT, name NVARCHAR(100),qty
INT);
CREATE PROCEDURE myProc (@tvp
myTableType READONLY) AS
UPDATE Inventory SET
qty += s.qty
FROM Inventory AS i INNER JOIN
@tvp AS tvp
ON i.id = tvp.id
GO
 Reduce client/server round trips
 Do not cause a statement to recompile
TVP Client Stack Support

SqlDbType.Structured





ADO.NET Example using DataTable
Using (MyConnection){
//Create a data table
DataTable dt = new DataTable(“TVPOrdersDataTable”);
dt.Columns.Add(“ProductType”, typeof(string));
dt.Columns.Add(“Quantity”, typeof(int));
// Add rows
dt.Rows.Add(“Canon Digital Camera”, 20);
dt.Rows.Add(“June”, 10);
dt.Rows.Add(“Xbox-360”, 8);
// Create a command and bind parameter
SqlCommand tvp_cmd = new
SqlCommand(“sp_UpdataInventory”,
MyConnection);
SqlParameter tvpParam =
tvp_cmd.Parameters.AddWithValue(
@OrdersTvp, dt);
//Execute command
tvp_cmd.ExecuteNonQuery();
SqlCommand command =
new SqlCommand(string.Empty, sqlConnection);
command.CommandText = "insert into MoviesRented
values(@customerId, @MovieID, @RentalDate,
@DueDate)";
….
// create a parameter for RentalDate
SqlParameter rentDateParam = new SqlParameter("RentDate",
System.Data.SqlDbType.DateTimeOffset);
rentDateParam.Value = DateTimeOffset.Now;
command.Parameters.Add(rentDateParam);
// create a parameter for DueDate
SqlParameter dueDateParam = new SqlParameter("DueDate",
System.Data.SqlDbType.DateTimeOffset);
dueDateParam.Value = DateTimeOffset.Now.AddDays(7);
command.Parameters.Add(dueDateParam);
….
// create a command to get the DueDate
SqlCommand command =
new SqlCommand(String.Empty, sqlConnection);
command.CommandText =
"select DueDate from MoviesRented where MovieId = @MovieId";
…
// Execute the DataReader
//
using (SqlDataReader dataReader = command.ExecuteReader())
{
if (dataReader.Read() == false)
{
Console.WriteLine("Movie has not been rented");
}
DateTimeOffset dueDate =
dataReader.GetDateTimeOffset (0);
Console.WriteLine("Movie due back on : {0}", dueDate);
}










// Poll for completion
IAsyncResult result = cmd.BeginExecuteReader();
while(!result.IsCompleted) {
// do some work
}
SqlDataReader reader = cmd.EndExecuteReader(result);
// Use a Callback
IAsyncResult result = cmd.ExecuteReader(
new AsyncCallback( myDataCallback ));
// do other work…
// optionally wait using sync object
result.WaitHandle.WaitOne();
public void myDataCallback( IAsyncResult result ) {
SqlDataReader reader = cmd.EndExecuteReader(result);
}


















public SqlDataReader GetProducts(int Category) {
SqlCommand cmd = new SqlCommand(
"Select ProductName, UnitPrice from Products " +
"where CategoryID = @CatID", cnn);
cmd.Parameters.Add("@CatID",Category);
cmd.Notification = new SqlNotificationRequest(
Category.ToString(), // message
"myQueue",
// message body
3000);
// timeout
return cmd.Execute();
}
public void WaitForChanges() {
SqlCommand cmd = new SqlCommand(
"Receive message_body from myQueue " +
"WITH wait_for_results", cnn);
cmd.CommandTimeout = 0;
int category = (int)cmd.ExecuteScalar();
Console.WriteLine("Category {0} changed.",category);
}




public void LoadFromDataReader(IDataReader reader)
{
// Copy the Data to SqlServer
SqlBulkCopy bcp =
new SqlBulkCopy( connectString );
bcp.DestinationTableName = "Customers";
bcp.WriteToServer( reader );
}














SqlConnection cnn = new SqlConnection(connectString);
cnn.Open();
SqlCommand cmd =
new SqlCommand("SELECT p FROM PointTable", cnn );
SqlDataReader reader = cmd.ExecuteReader();
while( reader.Read() )
{
Point point=(Point)reader[0];
Console.WriteLine(
"x:{0}, y:{1}", point.x, point.y );
}
cnn.Close();
Aggregates
AVG
CHECKSUM_AGG
COUNT
COUNT_BIG
MAX
MIN
STDEV
STDEVP
VAR
VARP
String Functions
ASCII
CHAR
CHARINDEX
DIFFERENCE
LEFT
LEN
LOWER
LTRIM
nchar
PATINDEX
QUOTENAME
REPLACE
REPLICATE
REVERSE
RIGHT
RTRIM
SOUNDEX
SPACE
STR
STUFF
SUBSTRING
UNICODE
UPPER
Math Functions
ABS
ACOS
ASIN
ATAN
ATN2
CEILING
COS
COT
DEGREES
EXP
FLOOR
LOG
LOG10
PI
POWER
RADIANS
RAND
ROUND
SIGN
SIN
SQRT
SQUARE
TAN
Date Functions
DATEADD
DATEDIFF
DATENAME
DATEPART
DAY
GETDATE
SYSDATETIME
SYSUTCDATETIME
SYSDATETIMEOFFSET
GETUTCDATE
MONTH
YEAR
System Functions
DATALENGTH
CHECKSUM
NEWID
CURRENT_TIMESTAMP
CURRENT_USER
HOST_NAME
USER_NAME
ISNUMERIC
ISDATE
 Data Access Across Tiers
 ADO.NET and SQL Server



















































http://forums.microsoft.com/MSDN/ShowForum.asp
x?ForumID=2035&SiteID=1

http://forums.microsoft.com/MSDN/ShowForum.aspx?Forum
ID=533&SiteID=1


© 2008 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries.
The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market
conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation.
MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.