Welcome to MSDN Blogs Sign in | Join | Help

 

This morning we announced the availability of the Visual Studio 2008 and .NET Framework SP1 Beta releases, and now you're probably wondering... well what's changed? Here goes...

Across the Entity Framework we have made numerous bug fixes (more than 200 of them). We've also made some significant documentation enhancements and exception message improvements to the Entity Framework.

You'll notice significant improvements specifically to the Entity Designer, where we made many of changes that you, our customers, had submitted to us over the last few months. You'll also notice a number of improvements to the Entity Framework Runtime including support for the new SQL Server 2008 types as specified below, query improvements and the introduction of the new EntityDataSource. Check out the lists below for a full description of changes.

 

Entity Designer

  • EDMX file format changes
    • The EDMX file has changed in this release and has been reorganized to have the designer section at the end
    • Users can no longer have an EDMX file open in the Entity Designer and the XML Editor at the same time

NOTE: As a result of these changes, EDMX files from older releases will need to be regenerated in this version of the Entity Designer

  • Update Model from Database
    • The current release improves this functionality and adds better support for iterative development scenarios. Among other improvements, it better handles new database tables and columns added to the database. It also accounts for entity type and property renames in the conceptual model and detects certain inheritance and mapping changes
    • The overall usability of the Update Model from Database wizard has also been improved based on feedback.
  • Printing and print preview
    • Conceptual models can be previewed and printed using the standard “File…Print” menu in Visual Studio
  • Getting around in the designer
    • Context menus have been organized to make common user tasks easier to use and discover
    • “Table Mapping” and “Stored Procedure Mapping” context menus added
    • Mini-toolbar on the scroll bar to quickly zoom, pan and navigate to an specific part of the diagram
  • UX and usability improvements
    • Improved validation error messages
    • Improved error navigation when double-clicking errors
    • Enhancements to property window contents for navigation properties to show association ends
    • F1 Help
    • Cut/Copy/Paste improvements for entity and properties
  • We fixed over 200 issues reported by customers since our Dec 2007 release. Here’s a bird’s eye view of the bugs fixed:
    • Bug with running the wizard when App/Web Config was open is fixed
    • Various mapping bugs are fixed
    • Much better support for mapping in TPH and TPT inheritance scenarios, better support for mapping stored procedures and better support for abstract types and hybrid mapping scenarios
    • Better build support; clean, rebuild, build all work better
  • Support for generating model & mappings from SQL Compact 3.5 SP1 databases

SQL 2008 Support

  • Full support for new Katmai data types: Date, DateTime2, DateTimeOffset and Time
  • Partial support (non-streaming only) for new Katmai FileStream data type

Metadata

  • Ability to have metadata files to come from any stream rather than just disk files
  • Change SQL Server provider manifest tokens to a human-understandable format (e.g. 2008, 2005, 2000)
  • Explicitly bind SSDL to a specific provider
  • Facets refactoring in CSDL

Query Improvements

  • Queries can now be compiled without an open connection
  • Simplification of generated store queries (e.g. less tables are joined for certain queries)

EntityClient

  • Exception refactoring in EntityClient
  • Big performance improvement on EntityClient result materialization
  • DbFunctionCommandTree introduced for non-SQL Server providers to handle retrieval through stored procedures

Object Services

  • Non-generic ObjectQuery base class with common services (e.g. ToTraceString, MergeOption)
  • Non-generic ObjectResult base class for generalized query handlers
  • DataContract full graph serialization and DataContract serialization of EntityReference and EntityCollections
  • OnContextCreated() partial method allows business logic hooks after ObjectContext creation
  • Improvements to RelationshipManager.GetAllRelatedEnds() to return all RelatedEnds even if they have not been previously accessed
  • Non-generic EntityReference base class helps to distinguish between EntityCollection and EntityReference without using reflection and provides access to the EntityReference.EntityKey
  • ObjectStateManager.GetObjectStateEntry(object entity) and ObjectStateManager.TryGetObjectStateEntry(object entity) methods were added back

LINQ to Entities

  • Support for EntityCollection.Count in queries
  • Improvements in using query span in combination with LINQ and CompiledQuery
  • Support for queries that test equality or group on an entity value
  • Circular reference detection in queries

EntityDataSource for ASP.NET

  • Declarative ASP.NET 2-way databinding against EDM
  • Design time support
  • Flattening of complex types and EntityReference keys
  • ASP.NET Dynamic Data Support

 

- The ADO.NET Team

We are very excited to announce that .NET 3.5 SP1 Beta 1 and Visual Studio 2008  SP1 Beta 1 are now available!

 

This beta marks the entry of the ADO.NET Entity Framework and ADO.NET Data Services (aka project Astoria) as part of the overall .NET/Visual Studio product install and will be the final beta before the RTM of these two technologies. In addition, this beta will introduce the new date time functions for SQL Server 2008 to LINQ to SQL.

 

The Entity Framework extends the reach of ADO.NET, providing a new data model that will be the foundation for a range of data services moving forward, and enhances the common ADO.NET provider model enabling a LINQ programming experience against 3rd party databases.  The Entity Framework designer in Visual Studio works with 3rd party databases as well and enables developers to visualize the data model being used by the application.

 

ADO.NET Data Services, provides the foundation for building the next generation of data-driven applications and services, building on Windows Communication Foundation (WCF) to provide an end-to-end experience for building data-centric REST based services in .NET.  The ADO.NET Data Services framework provides a REST based query model, a means of exchanging metadata (in terms of the Entity Data Model) and client and mid-tier API’s that let people build rich data services and clients in a way that is easier than ever before. You can start with the Entity Framework and expose relational data via the Data Services Framework, you can expose non-relational data using a custom provider, or you can use some of the existing services that already expose these protocols including Live App Storage and Live Spaces Photos.


We invite you all to download this beta and start using these technologies today.

 

Jason Wilcox             

Product Unit Manager, DP Runtime

 

and

 

Britt Johnston

Product Unit Manager, DP Tools

Here are a few quick announcements about ADO.NET providers supporting the Entity Framework.  Enjoy!

 

Core Lab (Connectivity to Multiple Data Stores)

Core Lab was the first ADO.NET provider writer to support Beta 3 of the Entity Framework.  Their provider includes connectivity to Oracle, MySQL, PostgreSQL and SQLite databases.  For more information, see the announcement on the following pages: http://crlab.com/news/2007/directs430.html and http://crlab.com/news/2008/dcsqlite100.html.

 

IBM

IBM has released a public beta for their ADO.NET provider that works with Beta 3 of the Entity Framework.  For more information, see the announcement on the following page: http://www-128.ibm.com/developerworks/forums/thread.jspa?threadID=203893.  IBM also demonstrated their provider in an end-to-end application building scenario using the Entity Framework designer at recent VS Live conference in San Francisco.

 

MySQL

At the recent MySQL conference in Santa Clara, Reggie Burnett and I co-presented a session talking about MySQL, LINQ and the ADO.NET Entity Framework.  As part of the session, we demonstrated using LINQ, Entity SQL and ADO.NET Data Services to access a MySQL database using Beta 3 of the Entity Framework.

 

Note:  Big thanks to Reggie for helping to make this demo work even after injuring his knee.  Get well soon.

 

Npgsql (PostgreSQL connectivity)

Npgsql has released a beta of their PostgreSQL ADO.NET provider that works with Beta 3 of the Entity Framework.  You can download the provider at the following page: http://pgfoundry.org/frs/download.php/1730/Npgsql2.0beta3-bin-EntityFrameworkBeta3.zip.  For more information on the release, please see the following page: http://pgfoundry.org/forum/forum.php?forum_id=1307.

 

David Sceppa

ADO.NET Program Manager

We’re gearing up for the next release of the SQL Server, and we are looking for people that have a passion for building great data access technologies and frameworks to help with the effort.  We have been very busy recently releasing:

·         Microsoft .NET Framework 3.5 (includes .NET Framework Data Provider for SQL Server aka SqlClient)

·         Microsoft SQL Server 2008 Feature Pack CTP, February 2008 (includes Microsoft SQL Server 2008 Native Client)

·         SQL Server 2005 Driver for PHP Community Technology Preview (February 2008)

·         Microsoft SQL Server 2005 JDBC Driver 1.2

If you are interested in designing the next set of API’s and tackling challenging technical subjects across all our SQL Server data access stacks and want to work for a team who is focused on shipping great technologies, we’re interested in hearing from you. Drop me a line directly at ddove@microsoft.com.

Debra Dove
Lead Program Manager

It's settled! The Entity Framework (and the Entity Designer) along with ADO.NET Data Services will RTM as part of the Visual Studio 2008 and .NET 3.5 SP1 releases!

Unfortunately, we don't have official release dates at this point, but stay tuned. You'll also want to keep an eye out for the upcoming SP1 Beta 1, which will be your next chance to check out updated bits for both of these products.

Elisa Flasko
Program Manager, Data Programmability

Since posting on the topic of design-time and runtime connectivity to pre-release versions of SQL Server 2008 on the Data blog in November, the set of affected clients (applications, runtimes, and operating systems) have been officially released: Microsoft Visual Studio 2008, Microsoft .NET Framework v3.5, Microsoft Vista Service Pack 1, and Microsoft Windows 2008. Runtime connectivity from a client system configured with any of these released products to SQL Server 2008 November CTP or later provides full runtime access to the following features (for design-time functionality, see below):

·         Table-Valued Parameters

·         New date/time data types

·         Large user-defined types

·         Support for very large FILESTREAM-attributed column data

Design-Time Connectivity Between Visual Studio and SQL Server 2008

Developers using Visual Studio 2005 or Visual Studio 2008 design tools will receive an error when trying to open a database on any pre-release instance of SQL Server 2008 without installing a Visual Studio patch. Pre-release patches for Visual Studio 2008 and Visual Studio 2005 enable the following Visual Studio functionality for SQL Server 2008:

·         Server Explorer successfully connects to SQL Server 2008, and database objects such as stored procedures and table data can be viewed and edited.

o   Note that table schemas still cannot be viewed or edited in this release.

·         SQL CLR projects that target SQL Server 2008 can be created and deployed to the server.

·         T-SQL and SQL CLR debugging are now enabled for SQL Server 2008.

·         Data binding features in Client and Web Projects are enabled.

 

Pre-release versions of the design-time patches are currently available: the Visual Studio 2008 CTP patch is available for download here and the Visual Studio 2005 CTP patch is available for download here. Final versions of the patches will be available in the near future. For more information please see the "Connecting to Microsoft SQL Server 2008 from Microsoft Visual Studio 2005 and 2008" whitepaper on MSDN.

 

 

Debra Dove

Program Manager Lead, Data Programmability

The “Update Model from Database” feature in the CTP2 of the EDM designer is greatly improved in the next designer release. It now supports iterative development scenarios by adding new database tables and columns to the schema, correctly handling type and property renaming in the model, and detecting certain inheritance and mapping changes. We’ll explore these scenarios in this blog post, as well as some of the usability changes that we have made. We’ll also talk about some of the limitations of the current implementation and discuss how we see this feature evolving.

 

To begin, we will use the Northwind database and bring in the Products table:

 

 

Next, we rename “Products” to “Product” and rerun Update Model from Database – in the next release, this option will be available from the designer context menu, here is a preview:

 

 

Note that we’ve also added shortcuts to both the table mapping and stored procedure mapping UIs.

Update Model from Database now looks like this:

 

 

We’ve moved the Refresh and Delete sections to make the interface more familiar.

To clarify the behavior of these tabs – the objects they show are all database objects:

-          Add shows objects that are in the database but not in the model.

-          Refresh shows objects that are both in the database and in the model.

-          Delete shows objects that are in the model but not in the database.

Because the wizard always regenerates the SSDL – any changes made to the SSDL will be lost on refresh - the update and refresh lists are read-only. We are looking at solutions that will enable merging of changes in the future.

 

We add the Orders, Order_Details, and Suppliers tables to our model by checking their checkboxes and clicking on “Finish”:

 

 

The takeaway here is that the wizard now correctly handles renames. However, we’ll see a number of validation errors, the first of which is:

Problem in Mapping Fragment(s) starting at line(s) (110, 176): Non-primary-key column(s) [SupplierID] being mapped in both fragments to different conceptual side properties - data inconsistency is possible because the corresponding conceptual side properties can be independently modified.

 

The Entity Framework is telling us that column SupplierID in table Product is mapped twice. What happened was that the initial import, which included only one table, did not create the association, and so the SupplierID field was surfaced as a property. If we look at the mapping for the association between Product and Suppliers we see that that association maps to the SupplierID column:

 

 

This is a scenario where the Update Model Wizard will not help us, as part of its policy is to avoid deleting any part of your model.  So we delete the SupplierID property from the Product type, and the model validates.

 

For our next step, we will make a some changes to the database:

-          Add a new bit column called “IsCurrent” to the Suppliers table.

-          Delete the “ContactTitle” column from the Suppliers table.

Once those changes are made, we update the model again, and this is what the Suppliers type looks like:

 

 

 

We also see a validation error:

Property ContactTitle is not mapped or used in a condition.

 

The wizard has added the new property to our type – another requested behavior. But, it has not deleted the ContactTitle property, because of the policy of not deleting elements from your model. So, we delete the ContactTitle property manually.

 

The next set of database changes will showcase the new mapping analysis feature in the wizard:

-          Add a table for new kind of supplier, call it PremiumSuppliers. Give it two columns, as shown below.

-          Add a SupplierContract table to our database to hold a large contract document and additional metadata. Give it three columns as shown below.

-          Add PK to PK constraints between these two tables and the Suppliers table, with the primary key table being the Suppliers table.

 

 

 

Update the model again, this time adding the two new tables. The relevant part of the model should look like this:

 

 

 

Now – we will copy and paste the properties from SupplierContracts to Suppliers and delete the SupplierContracts type. We will then go into the table mapping view for Suppliers and map it to the SupplierContracts table by clicking on the “<Add a Table or View>” cell and selecting “SupplierContracts”. The mapping view will look like this:

 

 

 

I have highlighted the one place where you will manually need to make a change: The SupplierContractID column must be mapped to the ID of the Suppliers type in order for the Entity Framework to understand how to construct the appropriate database queries.

 

Next, we delete the association between PremiumSuppliers and Suppliers and make PremiumSuppliers inherit from Suppliers. We then delete the PremiumSupplierID property from PremiumSuppliers since the key is now inherited from Supplier, and we fix the mappings as shown:

 

 

The relevant part of our model now looks like this:

 

 

 

Finally, we update the model again…and the model does not change! A bit anticlimactic after all this work, but consider: The wizard has analyzed the mappings and noticed that the two PK-to-PK associations have been replaced: One with an inheritance relationship, the other by mapping one type to two tables. Using this information, it avoids bringing these associations back into your model.

 

A few final notes about the wizard’s limitations:

-          It does not update the types of properties when the corresponding database columns change.

-          It does not “resurrect” entity types – once you have deleted a type, the only way to get it back is to recreate it manually, or delete the corresponding SSDL by hand in the XML editor.

-          It will also not “resurrect” properties.

-          If you change the keys that define your type, all current associations lose their identity and new associations will be brought in – you will need to delete old associations.

-          It cannot detect database object renaming – renames will show up as the deletion of an old object and the addition of a new one.

 

These limitations aside, we think you will find the new functionality both useful and more usable. We look forward to your feedback.

 

Noam Ben-Ami,

Program Manager, ADO.NET Entity Framework Tools

There have been a few questions from the last performance blog post about how the Entity Framework compares against other object relational mapping frameworks. The simplest way to compare the performance of Entity Framework with various competing products is to use query performance against SqlClient as a benchmark. This way, anyone can run the same query benchmarks against SqlClient with your current ORM product.

Here are the last two performance blog posts:

·         Exploring Performance Part 1

·         Exploring Performance Part 2

Here’s the configuration that I used to run my tests:

·         Visual Studio 2008.

·         SQL Express (installed with Visual Studio).

·         ADO.NET Entity Framework Beta 3.

·         Entity Framework Tools December 2007 CTP.

·         A C# console application built under the release mode configuration.

·         I’m using is Northwind as my database.

·         I’m running on my laptop, which is a dual core 2GHz processor with 3GB of RAM.

To create a benchmark for an ORM, we must read the data rows returned by the SqlDataReader into objects. It is not enough to simply iterate over the reader I used the same model as my previous performance blog post. Here’s the full EDM, but I really only used the Orders EntitySet.

 

To demonstrate performance in a slightly differently way, I added some paging queries to the scenarios from the previous posts. In the other performance blog posts, I compared tracking versus no tracking queries, and in these examples I am only showing the NoTracking cases. Objects are tracked when queried, added, or attached to the cached references inside a class owned by the ObjectContext called the ObjectStateManager. This tracking behavior is specified using the MergeOption. When updates to properties of the tracked objects occur, the properties are marked as modified and the original values are kept for performing updates back to the database. This enables users to simply write code against the objects themselves and call SaveChanges. The Entity Framework takes care of all the “heaving lift” of updating the database.

Query

For SqlClient queries, I created a class for Orders and get/set methods for properties. Here’s an example of the OrderID property. This is as simple as I can make it.

public int OrderID

{

    get

    {

        return _OrderID;

    }

    set

    {

        _OrderID = value;

    }

}

 

Here’s the SqlClient query I preformed. In the query, I specified each column individually instead using “*”. I wanted the comparison to include setting property values because that’s one of the benefits of using the Entity Framework.

SqlConnection con = new SqlConnection(connectionString);

con.Open();

 

SqlCommand cmd = con.CreateCommand();

string cmdText = "select CustomerID, EmployeeID, Freight, OrderDate, OrderID, RequiredDate, ShipAddress, ShipCity, ShipCountry, ShipName, ShippedDate, ShipPostalCode, ShipRegion, ShipVia from Orders order by OrderID";

cmd.CommandText = cmdText;

 

SqlDataReader dr = cmd.ExecuteReader();

while (dr.Read())

{

    Order o = new Order();

 

    if (!dr.IsDBNull(0)) o.CustomerID = dr.GetString(0);

    if (!dr.IsDBNull(1)) o.EmployeeID = dr.GetInt32(1);

    if (!dr.IsDBNull(2)) o.Freight = dr.GetDecimal(2);

    if (!dr.IsDBNull(3)) o.OrderDate = dr.GetDateTime(3);

    if (!dr.IsDBNull(4)) o.OrderID = dr.GetInt32(4);

    if (!dr.IsDBNull(5)) o.RequiredDate = dr.GetDateTime(5);

    if (!dr.IsDBNull(6)) o.ShipAddress = dr.GetString(6);

    if (!dr.IsDBNull(7)) o.ShipCity = dr.GetString(7);

    if (!dr.IsDBNull(8)) o.ShipCountry = dr.GetString(8);

    if (!dr.IsDBNull(9)) o.ShipName = dr.GetString(9);

    if (!dr.IsDBNull(10)) o.ShippedDate = dr.GetDateTime(10);

    if (!dr.IsDBNull(11)) o.ShipPostalCode = dr.GetString(11);

    if (!dr.IsDBNull(12)) o.ShipRegion = dr.GetString(12);

    if (!dr.IsDBNull(13)) o.ShipVia = dr.GetInt32(13);

 

    int i = o.OrderID;

}

 

con.Close();

 

When I ran this code 100 times, the average execution time was 4 milliseconds. I threw out the first run because of the one-time costs associated with connecting to the database and generating an execution plan. The first run time was 451 milliseconds.

Now moving over the Entity Framework, I performed the same query. I’m using compiled LINQ queries. Here’s the query that I performed.

public static Func<NorthwindEntities, IQueryable<Order>>

       compileFullQuery = CompiledQuery.Compile(

                                   (NorthwindEntities ne) =>

                                               (from o in ne.Orders

                                                select o)

                                   ); 

 

 

using (NorthwindEntities ne = new NorthwindEntities())

{

    foreach (Order or in compileFullQuery(ne))

    {

        int i = or.OrderID;

    }

}

 

When I ran this compiled LINQ query 100 times, the average execution time was 7.5 milliseconds. Again, I threw out the first execution at 1782 milliseconds.

Using an Entity SQL query instead of a LINQ query, I got slightly better times. Here’s the code for the query.

using (NorthwindEntities ne = new NorthwindEntities())

{

    ObjectQuery<Order> ordersQuery

              = ne.CreateQuery<Order>("SELECT VALUE o FROM Orders as o");

    foreach (Order or in ordersQuery.Execute(MergeOption.NoTracking))

    {

        int i = or.OrderID;

        count++;

    }

}

The average time after 100 runs, minus the first run, was 6 milliseconds. This time, the first execution was only 389 milliseconds. Here’s a chart that summarizes the time.

These are Beta 3 times and we are trying to make execution faster all the time. Now that we have a baseline comparison, I moved to a more common query in Web scenarios that use paging. Most folks are not going to query all the rows in a database to bind to some control, but a more realistic scenario would be to just query for a few entities at a time until all the entities are returned.

Paging Query

Paging is used to retrieve the data in chunks, such as many of us are used to when browsing for products to buy or search through the results of a Web search. For example, when I go to www.Live.com and search for “ADO.NET Entity Framework,” I may get a few million results, but I don’t want to see all those results in one web page. Instead, I get back chucks of 20 results on a page. Paging also enables me to skip to a particular page and get the result from a range of 20. In SqlClient, I can do this using the example below, where I just loop through this code for each page count and get 20 items at a time until all the 848 rows are consumed. That’s 43 queries to get all the data in more manageable pages.

SqlConnection con = new SqlConnection(connectionString);

con.Open();

 

SqlCommand cmd = con.CreateCommand();

string cmdText = "select TOP 20 CustomerID, EmployeeID, Freight, OrderDate, OrderID, RequiredDate, ShipAddress, ShipCity, ShipCountry, ShipName, ShippedDate, ShipPostalCode, ShipRegion, ShipVia from Orders where OrderID > @lastID order by OrderID";

cmd.CommandText = cmdText;

 

SqlParameter parameter = new SqlParameter("lastID", _nLastID);

cmd.Parameters.Add(parameter);

 

SqlDataReader dr = cmd.ExecuteReader();           

 

while (dr.Read())

{

    Order o = new Order();

 

    if (!dr.IsDBNull(0)) o.CustomerID = dr.GetString(0);

    if (!dr.IsDBNull(1)) o.EmployeeID = dr.GetInt32(1);

    if (!dr.IsDBNull(2)) o.Freight = dr.GetDecimal(2);

    if (!dr.IsDBNull(3)) o.OrderDate = dr.GetDateTime(3);

    if (!dr.IsDBNull(4)) o.OrderID = dr.GetInt32(4);

    if (!dr.IsDBNull(5)) o.RequiredDate = dr.GetDateTime(5);

    if (!dr.IsDBNull(6)) o.ShipAddress = dr.GetString(6);

    if (!dr.IsDBNull(7)) o.ShipCity = dr.GetString(7);

    if (!dr.IsDBNull(8)) o.ShipCountry = dr.GetString(8);

    if (!dr.IsDBNull(9)) o.ShipName = dr.GetString(9);

    if (!dr.IsDBNull(10)) o.ShippedDate = dr.GetDateTime(10);

    if (!dr.IsDBNull(11)) o.ShipPostalCode = dr.GetString(11);

    if (!dr.IsDBNull(12)) o.ShipRegion = dr.GetString(12);

    if (!dr.IsDBNull(13)) o.ShipVia = dr.GetInt32(13);

 

    // just do one response to make sure we have a get

    _nLastID = o.OrderID;

    count++;

}

 

con.Close();

 

 

When I ran this loop that consumed all the data in pages of 20 rows, the time averaged 18 milliseconds on 100 tries. Each iteration made 43 paging queries to consume all 848 rows. The first run was slower at 453 milliseconds and as before, I didn’t use that number in my average calculations. This means that every paging query took less than 1 millisecond; in fact when just doing the math, the time is rounded to 0.419 milliseconds.

Now let’s see how LINQ to Entities and Entity SQL compare to SqlClient.

Here’s the paging query for LINQ to Entities, again using compiled queries. (If somehow you managed not to notice how much simpler and cleaner the LINQ code is over that SqlClient then take a moment now to enjoy this much easier way to query and materialize data.)

public static Func<NorthwindEntities, int, IQueryable<Order>>

        compiledQuery = CompiledQuery.Compile(

                                    (NorthwindEntities ne, int lastCount) =>

                                        (from o in ne.Orders

                                         orderby o.OrderID

                                         select o).Skip(lastCount).Take(20)

                                    );   

 

 

using (NorthwindEntities ne = new NorthwindEntities())

{

    ne.Orders.MergeOption = MergeOption.NoTracking;

    foreach (Order o in compiledQuery(ne, _dbTotalRead))

    {

        int i = o.OrderID;

    }

}

 

The time for a full read over 100 iterations averaged 87 milliseconds, ignoring the first run. This equates to an average of 2 milliseconds per query. Below is the paging query expressed in Entity SQL.

using (NorthwindEntities context = new NorthwindEntities())