-
The "Entity Designer Database Generation Power Pack" is a downloadable addition to Visual Studio 2010 Beta 2 which includes some new database generation technologies. The original Database Generation feature in the Entity Designer in VS 2010 is extensible via Windows Workflows and T4 Templates. This Power Pack builds on these extensibility mechanisms and introduces the following:
- Basic Table-per-Hierarchy support. This is represented by the “Generate T-SQL via T4 (TPH)” workflow.
- The SSDL and MSL generation pieces can now be tweaked through T4 templates, both in TPH and TPT strategies through the “Generate T-SQL via T4 (TPT)” and “Generate T-SQL via T4 (TPH)” workflows.
- Direct deployment and data/schema migration are available through the “Generate Migration T-SQL and Deploy” workflow. This workflow will use the Team System Data APIs to diff our default T-SQL script against the target database and create a new script which will perform non-invasive ALTERs and data migration where necessary.
- A new user interface will now display when “Generate Database from Model” is selected – this acts as a “workflow manager” which will present to you our default workflows and allow you to create your own, customizable workflows based on your own strategy, script generation, and deployment requirements.
In addition, there are a few other things:
- Data-Tier Application support. This feature, first introduced in SQL Server 2008 R2, provides a new, consolidated way of managing SQL Server databases across multiple servers. You can think of it as an MSI installer package for your database server. For more information, see Sanjay Nagamangalam’s latest PDC session: http://channel9.msdn.com/posts/elisaj/Developing-Data-tier-Applications-using-Visual-Studio-2010/. The Database Generation Power Pack 1.0 supports generation of DACPACs and direct deployment of DACPACs to a SQL Server 2008 R2 CTP3 instance.
- Database Project support. Rather than just creating a T-SQL script, it may be more useful for a T-SQL developer to interact with the T-SQL inside a database project. This Power Pack can automatically ‘sync’ with a database project by importing our generated script into it – the project must be added to the same solution as the project containing the EDMX file and it must have the same name as the EDMX file – this requirement will go away in the future.
- Another small user interface in the form of a progress bar that replaces the “DDL” textbox in the last page of the “Generate Database from Model” wizard and can be declaratively created within the XAML of a Windows Workflow.
In this walkthrough, I will demonstrate how to install the Database Generation Power Pack 1.0.1, some of the key features in the new user interface, and how to achieve data and schema migration.
Installation
The only pre-requisite is Visual Studio 2010 Beta 2. Note that this extension will not work with Express editions. The Database Generation Power Pack is an MSI package that consists of a VSIX extension, a set of XAML flies, and T4 templates.
You can download the package from here: http://visualstudiogallery.msdn.microsoft.com/en-us/df3541c3-d833-4b65-b942-989e7ec74c87
Click on the “Download” link which will download the MSI. Launch the MSI, note the pre-release license and finish installing the setup package.
Setup
- Download the attached EDMX file locally (see end of this post)
- Save the attached SQL script locally (see end of this post)
- Open Visual Studio and create a new C# Console Application project.
- Right-click the project node and Add -> Existing Item -> BlogModel.edmx.
- Make sure you have CREATE DATABASE permission in the [master] database.
http://blogs.msdn.com/dparys/archive/2009/09/17/create-database-permission-denied-in-database-master-my-fix.aspx
Walkthrough
1. Open BlogModel.edmx in your project. Click on an area of the designer surface, look at the “Database Generation Workflow” property in the Properties window and note that we’ve added six new workflows. We can select a new one from here but for now, keep the default workflow: “TablePerTypeStrategy.xaml (VS)”
2. Right-click on the designer surface and select “Generate Database from Model…”. You will be presented with the new user interface:
3. You can think of this user interface as a more advanced version of the property window selector. On the left pane is a list of all workflows available which we aggregate from three locations:
- VS directory: %vsinstalldir%\common7\ide\extensions\microsoft\entity framework tools\dbgen
- User directory: %localappdata%\microsoft\visualstudio\10.0\extensions\microsoft\entity framework tools\dbgen
- The project that owns the current EDMX file
The right is a ‘details’ view which shows the options you can select, which options are available for the selected workflow, and buttons for deleting, cloning, and selecting the workflow. Making any changes to the workflow will automatically save it (as of version 1.0.1).
4. All of the workflows in the left pane are installed in the VS directory. We discourage you from editing these workflows since we may update them in the future. Therefore, the only operation available to you for these default workflows is cloning. The two buttons on the right of the toolbar allow you to clone the workflow to your user directory and to your project, respectively:
5. Click on the “Generate Migration T-SQL and Deploy” workflow in the list and click “Select Workflow for Database Generation”. Notice the green tick mark in the left pane now indicates that the “Generate Migration T-SQL and Deploy” workflow is selected. If your properties window is open, also notice that “Generate Migration T-SQL and Deploy.xaml” is selected in the “Database Generation Workflow” property.
6. Hit the “Next >” button at the bottom, and now you’re presented with the data connection page that you’re familiar with in basic Model First.
7. Select a ‘New Connection’, choose ‘.\sqlexpress’ as your Server name, and type in ‘BlogDb’ as the database name. Hit OK. VS will prompt you to create this database – select Yes. If you run into an error like “Permission denied in master”, make sure you have CREATE DATABASE permission (see the link above in ‘Setup’). Click ‘Next’ out of the data connection page.
8. You will see the Summary Page, but the “DDL” textbox has been replaced by a new progress bar which will track the progress of the overall workflow. If everything proceeds successfully, the progress bar should finish.
9. Hit Finish out of the Summary page, and the required store model (SSDL) and mappings (MSL) are created. Note that the T-SQL was never shown in the database generation process and it never opened in the editor afterwards. If you would like to tweak this workflow so that it follows the usual database generation process (not directly deploy, but open the migration script in the T-SQL editor) then using the new ‘Workflow Manager’, you can clone the workflow into your user directory, rename it, set the ‘Script Generation’ option to ‘Migration T-SQL’, set the ‘Deployment’ option to ‘None’, and select it for database generation.
10. Now open the Server Explorer (View -> Server Explorer) and notice that we’ve directly deployed to the database (if it’s already open, then right-click on the ‘Tables’ folder and select ‘Refresh’)
11. Now let’s insert some data – open up the [blogmodel.sql] script in Visual Studio and choose Data -> Transact SQL Editor -> Execute SQL. Connect to ‘.\sqlexpress’, and execute the script. You should see ‘Query executed successfully.’ Under the ‘Messages’ pane in the T-SQL editor.
12. Go back to the model – now let’s say we want to add comments to the posts in our blog and add a description to each post in our blog.
- Add in a ‘Comment’ Entity Type with ‘Id’ (of Type: non-nullable Int32), ‘Text’ (String) and ‘Rating’ (Int32) properties.
- Add a nullable (this is important) String property to Post called “Description” and then add a 0..1:* association between Post and Comment. You can choose to include foreign keys/navigation properties or not, it won’t matter. Without navigation properties and with foreign keys, it should look like this:
13. Right-click on the designer surface again, Generate Database from Model. Click ‘Next’ past the Workflow Manager. Since the connection string is now present in app.config, you will not see the data connection dialog, and the workflow should immediately directly deploy the new T-SQL. Select ‘Finish’ out of the Summary and Settings page. Go back to Server Explorer, right-click on the ‘Tables’ folder and select ‘Refresh’. Notice that we’ve added the ‘Comments’ table.
14. Right-click the Posts table and select “Show Table Data”:
We have preserved the existing data and added a new, nullable column for the description. If you do not see the ‘Comments’ table and the new ‘Description’ column, check to make sure that the ‘Description’ property in your ‘Post’ entity is Nullable. A script that is generated with a non-nullable Description property will look to see if there is any data in the ‘Post’ and halt the script to prevent data loss.
Conclusion
In this walkthrough we:
- Looked briefly at the new user interface to manage workflows and select them for database generation.
- Demonstrated how the designer can generate a migration script and deploy it directly.
- Demonstrated data and schema migration from the Entity Designer.
You can expect more functionality in future version such as the ability to handle “renames” (although this Power Pack provides migration, it cannot identify a rename of an EntityType, for example – this will translate into a drop/create), a new Workflow Manager, the ability to manage T4 templates, better database project support, and more.
Finally, we’re presenting these options and new UI affordances as a way of gauging what is most important to you for the next version of our tools so we value your feedback greatly!
Thanks,
Adi Unnithan
Software Design Engineer
-
Do you want to help define the future of the Entity Framework? We are actively looking for Software Developer Engineers in Test (SDE/T). With the successful release of Visual Studio 2010 and the team moving to the next release, we could use your help in driving the vision for the next version of the product that is rapidly becoming the best ORM on the market. Use your technical and design skills to ensure that future versions of the Entity Framework meet our customers’ high expectations. You are a software engineer who understands the experience of creating data-oriented applications. This is a unique opportunity to help deliver a product whose target audience is other developers like you!
If you are interested, you can apply at careers link and/or send an email through the email link in this blog.
Please include your resume and contact information.
Eric Dettinger
Entity Framework Team, Microsoft
-
Note: The download links below have been disabled while we prepare to release a new refresh of the template that is compatible with Visual Studio 2010 Release Candidate.
Today we are releasing an updated version of the POCO entity generation templates that work with Visual Studio 2010 Beta 2. You can download them immediately using the Extension Manager inside Visual Studio 2010 Beta 2 or from the Visual Studio Gallery page, here for the C# version and here for the Visual Basic version.
Usage of the templates is described in the updated POCO Template Walkthrough.
The original version of this T4 template was included in the Entity Framework Feature CTP 1, and since we released the Feature CTP 2 last November without this feature, we have heard from lots of customers that they wanted us to work on a new version of it.
Besides being compatible with Beta 2, the new template includes a number of bug fixes, generated code improvements, handling of relationship fixup that includes support for Foreign Keys in the Model (see more details here about this new feature of Entity Framework) and compatibility with change tracking POCO Proxies and ObservableCollection<T>.
The POCO Template is not going to be part of Visual Studio 2010 in RTM. Instead the current plan is to continue delivering updates for it through the Extension Manager and the Visual Studio Gallery.
Known issues in this version
- The POCO Template does not work with ASP.NET WebSite projects: A bug in multiple output file support prevents the POCO Template from working on WebSite projects. A fix will be available in a future update. In the meanwhile, you can place the template in a separate class library project and add a reference to the class library from the WebSite.
- Running a query with Include and MergeOption equal to NoTracking may cause an exception: There is a problem in the interaction between the implementation of relationships fixup code in classes generated by the POCO template and the change tracking POCO Proxies enabled by the POCO Template. We are currently investigating this issue.
- Detach can cause nullable foreign keys properties to be nulled: The implementation of relationship fixup cannot distinguish the reason an entity is being removed from an object graph. When Detach is applied to an entity that is related to others through foreign key associations, fixup logic will react to references being nulled and elements being removed form collections and will set the corresponding FK properties to null. We are currently investigating this issue.
- The AssociationChanged event can be raised twice: The AssociationChanged event is raised twice with CollectionChangeAction.Add when fixup occurs in the model such that a collection is modified. We are currently investigating this issue.
Feedback is welcome
If you find any problem or you are missing any feature you would like to see us include in future versions, you can enter bugs and suggestions through the Microsoft Connect page for the Visual Studio 2010 & .NET Framework 4.0 Beta located here.
You can also provide feedback or asks your questions in the Entity Framework Pre-Release Forum.
Diego Vega,
Entity Framework Team
-
Introduction
The Portable Extensible Metadata is a subset of the schema metadata enabled scenarios (the most common ones) built on the Entity Framework Designer extensibility model that enable rich development experience in tools and auto-generation of code. Much in the same way that MIME is a mechanism for extending and annotating media with metadata, schema metadata is about extending and annotating storage elements from different systems with metadata. Amongst other features this will better enable the ability to auto-generate parts of an application.
Looking into the future, we would like to bake these concepts in as core elements into a domain so your feedback is really important. Please give it a try and let us know what you think. The steps below assume basic familiarity with the EDM and uses the AdventureWorks sample database, or any other database you choose, will work as well.
Walkthrough
Install
Launch the “Extension Manager” from the Visual Studio “Tools” menu. The download is available from the online gallery, and you can find it quickly by entering “Metadata” into the search field. The samples are available for download from the Visual Studio Gallery here:
http://visualstudiogallery.msdn.microsoft.com/en-us/e6467914-d48d-4075-8885-ce5a0dcb744d
A successful PEM install will display in the “Extension Manager”:
Add metadata to adjust the entity Display
There are scenarios in which the developer needs to adjust the entity display (like order and visibility) without affecting the data in the database.
1. Create a C# solution containing a Windows Form Application project.
2. Add a new, blank ADO.NET Entity Data Model to the web application.
3. If you do not have it already set up, add the AdventureWorks.MDF database to the web application’s App_Data folder.
4. Double-click the model file to open it with the designer.
5. Right click on the designer surface and select “Update Model from Database”.
6. Select the connection to AdventureWorks.MDF, which will be automatically created for you when the MDF file is added to App_Data. If you are using your own database, you may need to create a new connection to it.
7. Proceed through the update wizard, accepting all the defaults, adding no new objects. This process will set up the database connection for you.
8. Select an entity in the designer and note the properties grid displays the metadata items grouped in the Schema Metadata section:
9. Click on the ellipses next to the Display property to open the Configure Instance Layout dialog:
10. This dialog allows changing both the order (by pressing the up and down arrows) and the visibility (by un-checking the button next to affected property).
11. Let’s choose that the application will not display the rowguid and have the CarrierTrackingNumber being display first. Select the CarrierTrackingNumber item and click the up arrow until it is the top of the list. Un-check the visibility checkbox next to rowguid.
12. Click OK and close the designer
13. Open the edmx file using the Open With option and select XML Editor
14. Note that the metadata was persisted in the CSDL section as a new element (Display) created under the CarrierTrackingNumber property with attribute Order set to 0:
<Property Name="CarrierTrackingNumber" Type="String" MaxLength="25" Unicode="true" FixedLength="false" >
<pem:Display Order="0" Visible="true" xmlns:pem="http://schemas.microsoft.com/PEM/2009/01" />
</Property>
The metadata was persisted in the CSDL section as a new element (Display) created under the rowguid property with Visible attribute set to true:
<Property Name="rowguid" Type="Guid" Nullable="false" >
<pem:Display Order="5" Visible="false" xmlns:pem="http://schemas.microsoft.com/PEM/2009/01" />
</Property>
Validating data at the property level
A value constraint restricts the population of a value to a finite set of values specified either in full (enumeration), by start and end values (range), or some combination of both (mixture). The values themselves are primitive data values, typically character strings or numbers. Let’s constraint the UnitPrice to be between $0 and $1000 (products more expensive than $1000 are not allowed) and have it required when entering new data.
1. In the same SalesOrderDetail entity select the UnitPrice property and in the properties grid, click on the arrow next to the Validations to expand it:
2. Click on the ellipses next to the Validations collection property to open the Validations Editor
3. Click on the arrow on the Add button to display the available vaildators for the property data type (in this case decimal) and select Range:
4. Note that once the Range Validator was added to the Members list, the enforcement was automatically set to must. Must means that the definition is an absolute requirement and data violating the constraint will not be entered in the system.
5. Set the MinimumValue and the MaximumValue properties to the minimum and maximum (in this case 0 and 400). In case of violation, the user needs to be notified, so let’s set the ErrorMessage property to the text to be displayed to the user: “The values accepted are between 0 and 400. No change was performed to the database”.
6. Click on the arrow on the Add button to display the available validators and select Required:
7. Note that the enforcement was correctly set to must, so the Validator will be enforced, the only thing left is setting the ErrorMessage to the text to be displayed: “Please enter the UnitPrice value”.
8. Click OK to close the dialog
9. Close the designer and open the edmx file using the XMLEditor. Note that both validators are persisted in the CSDL section under the UnitPrice element:
<pem:Validations xmlns:pem="http://schemas.microsoft.com/PEM/2009/01">
<pem:Range MinimumValue="0" MaximumValue="400" ErrorMessage="The values accepted are between 0 and 400" Enforcement="Must" />
<pem:Required ErrorMessage="Please enter the UnitPrice value" Enforcement="Must" />
</pem:Validations>
10. Open the designer (double click on the edmx file in the solution explorer)
11. Right-click anywhere in the designer and select Add Code Generation Item…
12. Select in the PEM Validation Code Generator option and click Add
13. Note that in the solution explorer a new template file was created (PEMValidation1.tt) with an associated code file (PEMValidation1.cs).
14. Open the code file (PEMValidation1.cs) and note that code was generated for enforcing both validators set in the designer:
public bool Validate(out List<string> warnings, out List<string> errors)
{
bool isOK = true;
warnings = new List<string>();
errors = new List<string>();
//Required
if((this.ProductID == null))
{
errors.Add("ProductID\tError: Field is required");
isOK = false;
}
// Range
if((this.UnitPrice < 0) || (this.UnitPrice > 400))
{
errors.Add("UnitPrice\tError: The values accepted are between 0 and 400");
isOK = false;
}
Validating data at the entity level
Let’s consider a more advanced validation scenario with the following business rule: if UnitPriceDiscount value is specified then the SpecialOfferID needs to be specified and the other way around (if SpecialOfferID value is specified then the UnitPriceDiscount needs to be specified).
1. Select the SalesOrderDetail entity in the designer:
2. Click on the arrow to the Validations property to expand its items and click on the ellipses next to the Validations collection property to open the Validations Editor
3. Click on the arrow on the Add button to display the available validators for the entity and select Equality:
4. Note that once the Equality Validator was added to the Members list, the enforcement was automatically set to must. Must means that the definition is an absolute requirement and data violating the constraint will not be entered in the system
5. In case of violation, the user needs to be notified, so let’s set the ErrorMessage property to the text to be displayed to the user: “If UnitPriceDiscount value is specified, then the SpecialOfferID needs to be specified and the other way around. No change was performed to the database”.
6. Click on the ellipses next to the Fields property to open the Fields Editor.
7. Note that the available fields’ collection was automatically populated to all the fields in the entity. Select from the available fields on the left and add to the list on the right, the two fields participating in the business rule: UnitPriceDiscount and SpecialOfferID:
8. Click OK to close all dialogs
9. Close the designer and open the edmx file using the XMLEditor. Note that the equality validator is persisted in the CSDL section at the entity level:
<pem:Validations xmlns:pem="http://schemas.microsoft.com/PEM/2009/01">
<pem:Equality ErrorMessage="If UnitPriceDiscount value …." Enforcement="Must">
<pem:Field>SpecialOfferID</pem:Field>
<pem:Field>UnitPriceDiscount</pem:Field>
</pem:Equality>
</pem:Validations>
10. Open the designer (double click on the edmx file in the solution explorer)
11. Right-click anywhere in the designer and select Add Code Generation Item…
12. Select in the PEM Validation Code Generator option and click Add
13. Note that in the solution explorer a new template file was created (PEMValidation1.tt) with an associated code file (PEMValidation1.cs).Open the code file (PEMValidation1.cs) and note that code was generated for enforcing the Equality Validator:
public bool SetValidate(out List<string> warnings, out List<string> errors)
{
bool isOK = true;
warnings = new List<string>();
errors = new List<string>();
// Equality
if (!((SpecialOfferID == null && UnitPriceDiscount == null) ||
(SpecialOfferID != null && UnitPriceDiscount != null)))
{
errors.Add("\tError: If UnitPriceDiscount value is specified….");
isOK = false;
}
return isOK;
}
Conclusion
This walkthrough does not touch on some of the additional capabilities and concepts, such as: Subset (the set of instances of the source population must always be a subset of the population of the target population: "If a patient has second given name then the patient has first given name" but not the other way around); all Ring types (the ability to specify that no instance is related to itself: "no patient is treated by itself"); all Mutual (the constraints in which a number of correspondent types are true or false simultaneously: "A patient has aplastic anemia if AtLeast (or "All”, “Exactly” and “AtMost") two of the three mandatory blood tests get a low count") and all mutual derivatives: Exclusive (Mutual with AtMost), InclusiveOR (Mutual with AtLeast), ExclusiveOR (Mutual with Exactly). We will touch on those in the next blogs and releases.
Again, this release is mostly about getting your feedback before baking these concepts in as core elements into a domain, so please let us know what you think.
Irinel Crivat
Program Manager, Microsoft
-
I came across a few great resources on Entity Framework recently.
Check out the tutorial and the projects here: http://weblogs.asp.net/zeeshanhirani/archive/2008/12/18/my-christmas-present-to-the-entity-framework-community.aspx. This contains a very informative learning guide that includes many mapping examples, LINQ to Entities query examples, databases that are used in the examples, and much more.
The tutorial is based on the Entity Framework version 1 (introduced in .NET Framework 3.5 SP1).
Also, download this fantastic tool that lets you dynamically query Entity Framework models using LINQ: http://www.linqpad.net/EntityFramework.aspx (works with EF v1). The .NET Framework 4 Beta 2 version of the tool is available here: http://www.linqpad.net/beta.aspx.
Julia Kornich
Content Publisher, Entity Framework
-
This is the second of a two part blog series on using POCO proxies in the Entity Framework 4.0. The first post described the capabilities of proxies and details on how they work. Using proxies means your types aren’t exactly as your system expects. This can pose challenges for operations such as serialization where having the right type is critical. This post demonstrates the best practices for using proxies in scenarios where serialization is involved, either through WCF DataContract serialization or binary serialization.
Lazy Loading and Serialization
Lazy loading and serialization don’t mix well, and if you aren’t careful you can end up querying for your entire database just because lazy loading is enabled. Most serializers work by accessing each property on an instance of a type. Property access triggers lazy loading, so more entities get serialized. On those entities properties are accessed, and even more entities are loaded. It’s a good practice to turn lazy loading off before you serialize an entity. You can do this by setting the LazyLoadingEnabled property on the context to false:
context.ContextOptions.LazyLoadingEnabled = false;
WCF DataContract Serialization
It’s common to find a data access layer such as the Entity Framework in use as part of a WCF service. Services can query for entities, make updates to entities, run validation or other business logic. The entities that the service uses can be entity framework proxies, but there are some things to watch out for.
In the following example, a WCF service exposes an operation method that returns a Customer type:
[ServiceContract]
public interface INorthwindService
{
[OperationContract]
Customer GetCustomer(string id);
}
The implementation of this service method creates an ObjectContext and performs a query to retrieve a Customer by key. This Customer is then returned from the service:
public Customer GetCustomer(string id)
{
using (NorthwindEntities ctx = new NorthwindEntities())
{
Customer c = ctx.Customers.SingleOrDefault(x => x.CustomerID == id);
return c;
}
}
To clients of this service, the operation is going to return a type “Customer”. The WSDL for this service knows about the type “Customer”. Clients will thus know about the type “Customer” but will not know about proxy types and will not be using any of the proxy behaviors. This is a good thing because your clients do not have a direct line of sight to the database to do things like lazy loading. So what happens when you try to execute the service operation and it returns a “CustomerProxy” instead of a “Customer”? If you guessed “you get an exception”, you were right.
The DataContractSerializer can only serialize and deserialize known types. There are plenty of ways to specify the list of known types to a serializer, but for these services we don’t want the client to have to know about proxy types (remember, no line of sight). This means proxies should not be part of the set of known types for the serializer.
Instead what we want to happen is for the proxy instance to serialize as if it was just a plain “Customer” type and not a “CustomerProxy” type. Fortunately, there is a new .NET 4.0 feature called DataContractResolver which can help. A DataContractResolver can map one type to another one during serialization; in the case of proxies, it can help map a “CustomerProxy” type to a “Customer” type. As part of the Entity Framework in .NET 4.0, we included the ProxyDataContractResolver which is an implementation of a DataContractResolver to map proxy types to their regular POCO types.
.NET 4.0 Beta 2 Note: The ProxyDataContractResolver class in .NET 4.0 Beta 2 is not fully functional. Instead, please use the implementation described below.
The ProxyDataContractResolver
A DataContractResolver has two methods that map types and names during the serialization process. During serialization, .NET types are mapped to type names that are part of the serialization payload. This is done in the “TryResolveType” method. The code below includes the implementation of the ProxyDataContractResolver. The TryResolveType method determines if the entity’s type is a proxy or not, and if it is a proxy uses the non-proxy type name in the payload:
public class ProxyDataContractResolver : DataContractResolver
{
private XsdDataContractExporter _exporter = new XsdDataContractExporter();
public override Type ResolveName(
string typeName,
string typeNamespace,
Type declaredType,
DataContractResolver knownTypeResolver)
{
return knownTypeResolver.ResolveName(
typeName, typeNamespace, declaredType ,null);
}
public override bool TryResolveType(
Type dataContractType,
Type declaredType,
DataContractResolver knownTypeResolver,
out XmlDictionaryString typeName,
out XmlDictionaryString typeNamespace)
{
Type nonProxyType = ObjectContext.GetObjectType(dataContractType);
if (nonProxyType != dataContractType)
{
// Type was a proxy type, so map the name to the non-proxy name
XmlQualifiedName qualifiedName = _exporter.GetSchemaTypeName(nonProxyType);
XmlDictionary dictionary = new XmlDictionary(2);
typeName = new XmlDictionaryString(dictionary,
qualifiedName.Name, 0);
typeNamespace = new XmlDictionaryString(dictionary,
qualifiedName.Namespace, 1);
return true;
}
else
{
// Type was not a proxy type, so do the default
return knownTypeResolver.TryResolveType(
dataContractType,
declaredType,
null,
out typeName,
out typeNamespace);
}
}
}
The ApplyProxyDataContractResolver
Once you have a ProxyDataContractResolver, the next step is to instruct the DataContractSerializer to use it in service operations. This can be done by defining an operation behavior attribute that you can use on your service methods. The attribute class below shows how to do this:
public class ApplyProxyDataContractResolverAttribute : Attribute, IOperationBehavior
{
public void AddBindingParameters(
OperationDescription description,
BindingParameterCollection parameters)
{
}
public void ApplyClientBehavior(
OperationDescription description,
ClientOperation proxy)
{
DataContractSerializerOperationBehavior
dataContractSerializerOperationBehavior =
description.Behaviors.Find<DataContractSerializerOperationBehavior>();
dataContractSerializerOperationBehavior.DataContractResolver =
new ProxyDataContractResolver();
}
public void ApplyDispatchBehavior(
OperationDescription description,
DispatchOperation dispatch)
{
DataContractSerializerOperationBehavior
dataContractSerializerOperationBehavior =
description.Behaviors.Find<DataContractSerializerOperationBehavior>();
dataContractSerializerOperationBehavior.DataContractResolver =
new ProxyDataContractResolver();
}
public void Validate(OperationDescription description)
{
}
}
The final step to use the ProxyDataContractResolver is to modify your service methods to include this attribute:
[ServiceContract]
public interface INorthwindService
{
[OperationContract]
[ApplyProxyDataContractResolver]
Customer GetCustomer(string id);
}
Serializing back to proxies
Another frequent question is how to send POCO instances on the client tier back to a service tier and have them show up as proxies. This problem is more difficult and unfortunately, doesn’t have a good solution even in .NET 4.0. When the Entity Framework creates proxies, two things happen:
1. A proxy instance is created
2. All of the collection navigation properties are set with the appropriate EntityCollection<T>
The ProxyDataContractResolver doesn’t help in this case because the method ‘ResolveName’ used in deserialization only can return a type, not an instance of a proxy. This means that the resolver can only help with step 1. One possible option is to write your own custom DataContract surrogate. This does give you the option to instantiate your own proxy types using context.CreateObject<T>(), but it also requires you to implement a fair bit of your own logic to do circular reference detection and identity resolution. If you really need a proxy instance for a non-proxy POCO entity that was sent from a client to a service, the simplest solution is to copy the values sent from the client into proxy instances you create inside your service method.
Binary Serialization
Binary serialization works by serializing the memory an instance or graph of instances is using. It does not call property getters/setters like DataContract serialization does (if DataMembers are on properties). This has both advantages and disadvantages, but for proxies the main advantage is that proxy instances are not recreated by setting properties, the memory is just rehydrated. This allows proxies to be serialized and deserialized as proxy types. With binary serialization the proxy types need to be available. To do this, you can use the CreateProxyTypes method to ensure that all proxy types are available for a given MetadataWorksapce (it checks the proxy type cache, and create the proxy types that aren’t yet there):
context.CreateProxyTypes(new Type[] { typeof(Customer), typeof(Order) });
The one qualification with deserialization is that the instances come back as proxy types, but will not have any of the proxy behaviors.
Here is an example of using the techniques above to write and read an entity to a file using binary serialization:
class Program
{
static void Main(string[] args)
{
if (args[0] == "Write")
{
using (NorthwindEntities ctx = new NorthwindEntities())
{
Customer c = ctx.Customers.SingleOrDefault(x => x.CustomerID == "ALFKI");
WriteToFile(c, "Customer.txt");
}
}
else if (args[0] == "Read")
{
using (NorthwindEntities ctx = new NorthwindEntities())
{
ctx.CreateProxyTypes(new Type[] { typeof(Customer) });
Customer c = ReadFromFile<Customer>("Customer.txt");
// Once attached, the customer can be used again
ctx.Customers.Attach(c);
c.Name = “New Name”;
ctx.SaveChanges();
}
}
}
internal static void WriteToFile<T>(T obj, string filePath)
{
using (FileStream file = new FileStream(filePath, FileMode.Create))
{
(new BinaryFormatter()).Serialize(file, obj);
}
}
internal static T ReadFromFile<T>(string filePath)
{
using (FileStream file = new FileStream(filePath, FileMode.Open))
{
return (T)(new BinaryFormatter()).Deserialize(file);
}
}
}
In Summary
Proxies can be a great way to get additional functionality in your entities simply. You have to be willing to make concessions about the accessibility of your class and properties, as well as be willing to work with ICollection<T> if you are using change tracking proxies. Serialization can still be done with proxies, but it is a bit more work. Members of the EF team are thinking about how to improve the proxy experience even more by making it more flexible and customizable, as well as having better integration with other parts of .NET. Let us know your thoughts on what kinds of capabilities you’d like to see in extensible proxies for the Entity Framework.
Jeff Derstadt & Diego Vega
Entity Framework Team
-
The Entity Framework (EF) in .NET 4.0 introduces the ability to interact with entities with persistence ignorance (POCOs). While this favors separation of concerns, it also means that the entities will do less because they cannot talk directly to the data access layer. Another new concept in EF 4.0 is the idea of dynamically generated proxies for such entities. Opting into proxies is an easy way to get additional capabilities like lazy loading and change tracking, while still keeping the entity class definition and implementation simple.
This is the first in a two part series that describes how proxies work in the Entity Framework. The first post describes the kinds of proxies available in EF 4.0, how they work, and about the API for dealing with proxies. Although the behaviors of proxies like lazy loading can be quite easy to understand, the internal mechanics of how to make that work can be complicated. It is not a requirement to understand these details to use proxies, but we wanted to share our approach and get feedback. The second post will describe some of the best practices for using proxies in serialization scenarios.
Proxies in a Nutshell
Proxies are a form of dependency injection where additional functionality is injected into the entity. In the case of POCO entities, they have no dependency on the EF so cannot create or execute queries or tell the state manager about changes. In the EF, a proxy is a dynamically generated derived type of an entity that overrides various properties so that additional code can be run. In the case of lazy loading, this is the code to perform a navigation property load. In the simplified example below, the EF creates the derived type “EFCustomerProxy” and overrides the Orders property. In the getter for Orders, an extra method call is performed to DoLazyLoad() to perform the load of the Orders collection if it is not already loaded.
// POCO Type
public class Customer
{
public virtual ICollection<Order> Orders { get; set; }
}
// Dynamically Generated Type
public class EFCustomerProxy : Customer
{
public override ICollection<Order> Orders
{
get
{
DoLazyLoad();
return base.Orders;
}
set
{
base.Orders = value;
}
}
}
The EF generates proxy types on the fly using the AssemblyBuilder and TypeBuilder in the .NET framework. All the code to perform lazy loading and change tracking is added to the dynamically generated types using the Reflection.Emit APIs. Proxy types are created once per .NET type for each instance of metadata (more about this later), and these types are cached so they can be reused in the same AppDomain.
For the EF to be able to create a dynamically derived type, a couple of things need to be done:
- Proxy creation must be turned on. It is on by default, but there is a setting to turn it on or off:
context.ContextOptions.ProxyCreationEnabled = true;
-
It must be possible to create a derived .NET type in a separate assembly:
a. The class must be public and not sealed.
b. The class must have a public or protected parameter-less constructor.
c. The class must have public or protected properties
d. Certain properties must be virtual – depending on which properties are virtual, you can opt into more behaviors (see the sections on kinds of proxies).
Kinds of Proxies
The Entity Framework supports two kinds of proxies: proxies that can perform lazy loading, and proxies that also can perform change tracking.
Lazy Loading Proxy
Lazy loading is the ability for an entity to perform a query for related entities whenever a navigation property is accessed. In the following example, when lazy loading is enabled a query for the customer’s Orders is executed as soon as c.Orders is called:
using (var ctx = new NorthwindEntities())
{
Customer c = ctx.Customers.Single(x => x.Id == 1);
Console.WriteLine(c.Orders.Count);
}
In addition to the requirements for proxies in general, two things need to happen for lazy loading to be enabled for entities with persistence ignorance:
- Lazy loading must be enabled
context.ContextOptions.LazyLoadingEnabled = true;
In the runtime, lazy loading is not on by default. However, the default code generator for the Entity Framework includes an annotation that instructs code generation to add a line to your model’s derived ObjectContext constructor to turn lazy loading on – so it can appear that lazy loading is on by default.
- Navigation properties must be declared virtual
public class Customer
{
public virtual ICollection<Order> Orders { get; set; }
}
For collection navigation properties such as “Orders” above, the type of the property also can be important. In general, lazy loading proxies do not care what the type of the property is, whether it is an ICollection<Order>, a List<Order>, a HashSet<Order>, or a MyFancyCollection<Order> as long as there is a way to create that collection type (this is the case in general for POCO collections). The following collection types are supported:
- All concrete class property types (List<Order> for example).
- Interface property types that are assignable to a List<> or a HashSet<> (so ICollection<>, IList<>, and ISet<> all will work)
- Entities that supply the collection instance in the getter (so IMyFancyCollection<> will work as long as the getter returns an instance and the EF doesn’t have to create one).
What is not supported is exposing an interface for a property type that requires a specific concrete type. For example, if the property type is IMyFancyCollection<Order>, the EF does not know which kinds of collection types are assignable to an IMyFancyCollection<T>.
Change Tracking Proxy
Change tracking is important to any data access layer because it controls which INSERT, UPDATE, and DELETE commands are sent to the database. Entities with full persistence ignorance do not track any changes, but instead rely on a persistence framework such as EF to figure out what changes have been made to each entity. This is typically done via a snapshot mechanism. When a query is done for an entity, a copy of all the entities scalar and relationship properties is made and stored in the framework. At certain “sync points”, a diff is done between the current values of the entity and the copy. This can be expensive both in terms of the memory to store all the snapshots and to perform the diff. This cost can be especially high if there are a large number of entities in a context. Change tracking proxies help with this cost by injecting the ability for an entity to report changes directly back to the state manager, so no snapshot or diff is necessary.
In the following example, a query is done for a Customer c and the Name property is updated.
using (var ctx = new NorthwindEntities())
{
Customer c = ctx.Customers.Single(x => x.Id == 1);
c.Name = "New Name";
ctx.SaveChanges();
}
When no proxy is used, the query will cache a copy of the entity before returning the result. When the Name property us updated, the ObjectContext ctx does not know about the change until SaveChanges is called (which calls DetectChanges, the EF’s mechanism to perform a diff, by default). If change tracking proxies are being used, the ObjectContext knows not to create the copy of the entity, and when the change is made to the Name property, the entity is able to notify the ObjectContext’s ObjectStateManager immediately.
Change tracking proxies work by intercepting the calls that update an entity. These are all of:
- Scalar and complex property setters
c.Name = "New Name";
- Reference navigation property setters
c.Detail = new CustomerDetail { ID = c.ID };
- Collection navigation properties
ICollection<Order> collection = c.Orders;
To ensure that no changes are lost for change tracking proxies, you are required to allow the proxy to intercept all of these calls. This poses additional restrictions around your entity beyond those of lazy loading proxies:
- All mapped properties must be declared virtual and be public or protected
public class Customer
{
public virtual string Name { get; set; }
public virtual CustomerDetail Detail { get; set; }
public virtual ICollection<Order> Orders { get; set; }
}
- Collection navigation properties must be of type ICollection<T> and must have a getter and a setter
Change tracking proxies are stricter about the type of collection properties. This is because a collection is a separate instance from the entity so changes can be made without the proxy noticing. The Entity Framework solves this by setting an EntityCollection<T> instance as the collection property; EntityCollection<T> already knows how to report changes to the collection back to an ObjectContext. This collection is always set when a proxy instance is created, either through a query or through the CreateObject<T> method on the ObjectContext. This is why a setter is required for collection properties. However, once that EntityCollection<T> instance is set, it cannot be changed and the proxy ensures this by overriding the setter and throwing an exception if you try. You can still set a collection instance to the backing field of the property if you need it to be non-null for testing purposes or non-proxy use.
How to tell?
When you have an instance of an entity type, how do you tell whether you are working with a proxy or not? The ObjectContext contains several APIs for working with proxies, and you can use these to determine if you have a proxy or not. Here is a method you can write to tell if you have a proxy or not:
public bool IsProxy(object type)
{
return type != null && ObjectContext.GetObjectType(type.GetType()) != type.GetType();
}
The question of whether you have a proxy or not is interesting, but the more important question is whether it matters that you are working with a proxy or not. In many cases it should not, the entity’s definition is still the same. However, the behavior of your entity is changing and this is significant. With lazy loading, you no longer have to check whether a relationship navigation property is loaded or not so it allows developers to bake in certain assumptions (my collection will always be non-null and loaded), which can be a nice simplification and lead to a better separation of concerns.
There are cases in which you might want to verify that lazy loading and change tracking still work after you have made changes to your entity types. In EF 4.0, the proxy mechanism is internal, mainly because we did not have enough time to come up with a good public mechanism and fully test it given our other priorities, but it is our intention to do this. There are ways to determine proxy behavior that rely on internal EF details (such as interfaces the proxies implement), but it is best to avoid these in case these internal mechanisms change when proxies become more extensible. The best way to determine the kind of proxy you have is to write a unit test like this:
public void TestCustomerIsProxy()
{
using (NorthwindEntities ctx = new NorthwindEntities())
{
Customer c = ctx.CreateObject<Customer>();
c.CustomerID = "AAAAA";
c.CompanyName = "A";
ctx.Customers.Attach(c);
// Determine if the instance is a proxy
// If it is, proxy supports lazy loading
bool isLazyLoading = IsProxy(c);
// Make a change, see if it is detected
// If it is, proxy supports change tracking
c.CompanyName = "B";
bool isChangeTracking = ctx.ObjectStateManager
.GetObjectStateEntry(c)
.State == EntityState.Modified;
Assert.IsTrue(isLazyLoading && isChangeTracking,
"Wanted a change tracking proxy, but didn't get one");
}
}
Enforce Using Proxies
If you want to enforce using proxies throughout your application, one thing you can do is to make a protected parameterless constructor on your POCO object. This will prevent instantiation of your POCO classes in your stack and will require all entity class creation to go through the CreateObject<T> method on the ObjectContext class.
Proxy Equivalence
Another interesting point about proxies is their type equivalence: if you have a proxy for a Customer you retrieved with instance context1, can it be used later with a different ObjectContext instance context2? As mentioned earlier, in EF 4.0 a proxy type is generated for each .NET type and use in metadata. The point about metadata is important because metadata is what tells the Entity Framework which properties are the scalars and which are navigation properties from all the properties on the entity. The scenarios where this really matters are where you are re-using your entity types with different models, which is common when you have a large model that you have partitioned into several smaller models.
This means for a .NET type, Customer, using metadata in NorthwindEntities, a single proxy type is created and cached per AppDomain so it can be reused. If that .NET type, Customer is used with another model such as MyOtherModelEntities, a new proxy type will be created. To differentiate between these types, the pertinent metadata (the EntityType and the EdmProperties) is encoded using an SHA-256 hash and incorporated into the name of the type. This makes the type name look something like this:
System.Data.Entity.DynamicProxies.Customer_448F4B60EA59F871D551849C8E17777AED971E19438A72A130FF2D53E75C865C
As long as the .NET type is the same and the metadata contains the same information (same EntityType and EdmProperties), this name will be the same regardless of which machine the proxy type is created on. We’ll see why this is important later when we discuss binary serialization.
Change tracking of complex type properties
Similar to entity types, in Entity Framework complex types are mapped classes that have their own properties. However, complex types don’t have their own unique identity as entity types do. Typically, complex types appear in the model as properties on entities that contain nested members. The canonical example is the Address complex type property in the Customer entity type, where Address may have additional properties such as Street, City, Country, etc.
A change tracking proxy is capable of detecting when the complex type instance in a property gets completely replaced, like in this case:
customer.Address = new Address() { Street = "8th street",
City = "Redmond",
State = "WA" };
But when a nested property is changed in the complex type instance, a snapshot comparison is used to detect the change instead.
var customer = ctx.Customers.SingleOrDefault(c => c.CustomerID == 1);
customer.Address.Street = "";
ctx.DetectChanges();
Assert.AreEqual(
ctx.ObjectStateManager.GetObjectStateEntry(c).State,
EntityState.Modified);
In the code above, for instance, a call to DetectChanges is necessary in order to detect that the Address.Street property has been modified. By default, DetectChanges is invoked implicitly in SaveChanges, so invoking DetectChanges shouldn’t be necessary unless you need things like the ObjectStateEntry.State property to return the right value before saving.
Proxy Specific API
While one of the goals of POCO Proxies is to transparently substitute regular POCO instances, in some circumstances it is necessary to recognize their presence and to deal with the proxy types themselves. For those situations, the Entity Framework includes a few new APIs that help deal with proxies.
ContextOptions.ProxyCreationEnabled
As explained previously, the ProxyCreationEnabled flag controls whether the Entity Framework runtime will attempt to create proxy instances. The setting governs the behavior of query results materialization as well as of the CreateObject<T> method.
CreateObject<T>
When proxy creation is enabled and a particular entity type fulfills the requirements to create proxies, queries with that result type will automatically return POCO proxy instances. However, if you use the “new” operator to create a new entity of the same type, you will obtain a regular POCO instance.
In order to obtain a new proxy instance without querying the database, for instance to attach it or add it to the ObjectContext, you can use the CreateObject<T> factory method.
The generic argument of this method can be any concrete reference type – abstract classes, interfaces and value types are not supported.
When an arbitrary CLR that is not mapped as an entity is passed to CreateObject<T>, the method will attempt to use any parameterless constructor to create and return a new instance of it. If however the T is a POCO type that matches an entity type in the metadata of the ObjectContext instance, CreateObject<T> will look at the state of ContextOptions.ProxyCreationEnabled to determine whether to return an instance of T or to attempt to create a proxy.
Note: CreateObject<T> will not throw an exception if the CLR type used in the generic argument doesn’t comply with proxy requirements. Instead, it will simply try to create and return an instance of the original CLR type.
CreateObject<T> is meant to be used in application code as a uniform way to obtain entity instances. If your application always uses CreateObject<T> instead of the operator “new”, then proxies will be created as appropriate depending on the current configuration of ProxyCreationEnabled and the conditions attained by the POCO type.
In addition to the version of CreateObject<T> in ObjectContext, there are two overloads of the method on ObjectSet<TEntity> that are more restrictive.
A non-generic overload of CreateObject exists on ObjectSet<TEntity>, which will simply attempt to return a proxy instance of type TEntity. A generic overload of CreateObject<T> on ObjectSet<T> can be used to return instances of types derived from TEntity, which comes handy on inheritance scenarios.
As an example, the following two calls are equivalent:
var b1 = context.CreateObject<Blog>();
var b2 = context.Blogs.CreateObject();
Note: CreateObject<T> will only create an entity instance; it will not add it or attach it automatically to the ObjectContext. If you want to add or attach the instance, you have to do so explicitly:
var b2 = context.Blogs.CreateObject();
context.Blogs.AddObject(b2);
GetObjectType
This static method defined in ObjectContext returns the actual entity type for a given proxy type. Similar to CreateObject<T>, GetObjectType works with any arbitrary type, but it has especial behavior when a proxy type is passed as the input. For any arbitrary non-proxy type, the method returns the same type it receives as an input. When a proxy type is recognized however, the method will return the corresponding original POCO type. In the following example, the method will return the type Blog:
var blog = context.Blogs.CreateObject();
var blogType = BloggingContext.GetObjectType(blog.GetType());
CreateProxyTypes
Normally, POCO Proxy types are generated lazily at run time: it is not until some query asks for results of a particular POCO type that the corresponding proxy type is created. Nonetheless, in some situations it may be necessary to create the proxy types in advance.
The CreateProxyTypes method can be used to trigger the creation of a set of proxy types without actually producing any instance.
This method can be useful when serializing an object graph across AppDomain boundaries, to make sure that the proxy types actually exist in the target environment. If the types didn’t exist, deserialization would fail.
This method will create the corresponding proxy types for the entity types passed as parameter, according to the metadata loaded in the ObjectContext. We will explain the usage of the method in more detail when we cover binary serialization of proxies. In the meantime, here is a simple example of how to use this API:
context.CreateProxyTypes(new Type[] { typeof(Customer), typeof(Order) });
GetKnownProxyTypes
This static method returns an enumeration containing all the proxy types that have been created so far in the AppDomain. In serialization scenarios, the method can be used to obtain all the types that the target environment should already contain and the serializer itself should recognize. Usage is as follows:
var knownTypes = BloggingContext.GetKnownProxyTypes();
In Summary
In this post we looked at lazy loading proxies and change tracking proxies as well as the tradeoffs you face when opting into using these capabilities. The next post in this series will be about serializing proxies and some of the issues you might face when trying to accomplish this as not all serialization technologies are built with proxies in mind. If you have any feedback on the general experience of using proxies, or more questions on our implementation, we’d appreciate hearing from you.
Jeff Derstadt & Diego Vega
Entity Framework Team
-
This walkthrough will demonstrate how to use the new Plain Old CLR Object (POCO) support in Entity Framework 4.0 to develop an application using Test-Driven Development (TDD).
In the first release of EF, entity classes had to inherit from EntityObject or implement one of the EF interfaces, which meant your classes had to have direct dependencies on the EF. As a result, writing unit tests that verified the logic for just your domain objects was challenging. The tests would have to interact with the database directly, which violates the principle of persistence ignorance, and results in the tests running orders of magnitude slower.
With Entity Framework 4.0, you can use the Repository and Unit of Work pattern to create domain entities that are completely EF-agnostic. With the hard dependency on the EF removed, it’s much easier to create fakes and mocks of these objects when writing unit tests. These tests no longer need to hit the database at all, offering a clean separation of concerns, reducing complexity, and making unit tests run significantly faster.
Read More...
-
The goal of this walkthrough is to demonstrate a basic scenario for the use of the Self-Tracking Entities feature of Entity Framework.
Self-Tracking Entities consist on a set of code generation templates based on Text Template Transformation Toolkit (T4) technology that is used to generate entity types that have the ability to record changes on scalar and complex property values, and on reference and collection navigation properties, independently of the Entity Framework.
The main scenario we are trying to address with Self-Tracking Entities is one in which a WCF service exposes a series of operations that return entity graphs, then a client application can manipulate that graph and submit the modifications to another service operation that validates changes in the graph and then applies them to the database store using Entity Framework.
While the following walkthrough uses C#, versions of the Self-Tracking Entities template exist for both C# and Visual Basic, and all the concepts described apply as well to the Visual Basic version.
Requirements
1. This walkthrough requires Visual Studio 2010 Beta 2.
2. The Microsoft Entity Framework Feature CTP 2 that is described here.
3. A local SQL Server 2008 Express instance has to be installed as SQLEXPRESS. Otherwise, changes to the connection string in the web.config file or regenerating the database from the included SQL scripts may be necessary.
4. Download and extract the initial solution attached to this post.
Read More...
-
This post covers Code Only improvements in the CTP2 release for VS 2010 Beta2. This walkthrough shows how you can change the default model like specifying property facets and navigation property inverses as well change the default mapping by changing the default inheritance strategy and table and column names. You can learn more about the CTP2 Code-Only improvements from our blog post on the EFDesign blog.
Code Only ships as part of the Microsoft Entity Framework Feature CTP 2. The CTP works on top of the latest version of the Entity Framework released as part of .NET 4.0 Beta 2.
Requirements
- This walkthrough requires Visual Studio 2010 Beta 2
- The Microsoft Entity Framework Feature CTP2, that can be downloaded from here.
- A local SQL Server 2008 Express instance has to be installed as SQLEXPRESS.
- Download and extract the initial solution attached to this post.
Read More…
-
A new feature of the Entity Framework in .NET 4.0 is the ability to return collections of complex type instances from stored procedures. In the next public release of the designer, we have enriched this functionality by adding the ability to automatically create these complex types by querying stored procedure metadata from the database server. To demonstrate this feature, we will use the Northwind database, and we will focus on a stored procedure called “CustOrdersDetail”. Looking at the designer’s model browser window after we reverse engineer Northwind, we see:
Double-clicking “CustOrdersDetail” brings up the “Add Function Import” dialog:
We click “Get Column Information” in order to see the metadata returned by the server about this stored procedure’s return columns. Then, we click on the “Create New Complex Type” button, and the designer automatically creates a new complex type that matches the shape of the data returned from the stored procedure:
To make life more interesting (and realistic,) let’s rename some of the properties in the generated complex type: ProductName to Name, and UnitPrice to Price. To keep things running, we then need to fix the function import’s mappings to look like this:
Finally, to simulate some real-world churn, we change the stored procedure’s return shape: We’ll rename “UnitPrice” to “UnitPricing”, add a new column called “Foo”, and delete “Quantity”:
ALTER PROCEDURE CustOrdersDetail @OrderID int
AS
SELECT ProductName,
UnitPricing=ROUND(Od.UnitPrice, 2),
Discount=CONVERT(int, Discount * 100),
Foo = '!',
ExtendedPrice=ROUND(CONVERT(money, Quantity * (1 - Discount) * Od.UnitPrice), 2)
FROM Products P, [Order Details] Od
WHERE Od.ProductID = P.ProductID and Od.OrderID = @OrderID
That done, we double click on the function import again, get column information, and this time, click on the “Update” button. The designer will now inspect the mappings, the existing complex type, and the new return shape, and produce these proposed changes to the complex type:
As you can see, “Foo” will be added, and “Quantity” will be deleted. In addition, the mappings are used to map “Name” to “ProductName” meaning no action will be taken for it. Finally, since “UnitPricing” is seen as new, “Price” will be deleted and “UnitPricing” will be put in its stead. Since we do not want this, we will rename the column in the function import’s mapping to “UnitPricing” and rerun the above process. This time we get:
Which is what we would want.
In conclusion, the designer now exposes the Entity Framework’s new ability to return complex type instances from stored procedure. On top of this, it adds some features to make this capability easier to use and to iterate over. In future releases of Visual Studio, we will improve the iterative features and look into supporting batch imports of stored procedures, so that you will not need to import them one by one. We look forward to your feedback.
Noam Ben-Ami
Program Manager, Entity Designer
-
The ADO.NET Providers team still needs your input. This is the last week to answer our ADO.NET Managed Providers Planning survey. Help us to make the decisions that will benefit our database community.
The survey can be found at http://blogs.msdn.com/adonet/archive/2009/11/01/the-ado-net-providers-team-wants-to-hear-your-opinion.aspx.
Thanks
Luiz Fernando Santos
Program Manager, SQLClient
-
Last March Alex James posted to our design blog about our plans for adding foreign keys to the entity framework. Since then we’ve pushed forward with implementing FK associations and properties and have included them in Visual Studio 2010 Beta 2. This article offers a walkthrough of foreign key relationships in the EF and how they’re useful in VS2010 Beta2. For more information, the documentation and a number of blogs offer useful background about the logic behind adding EF foreign key relationships; here are a few links:
http://blogs.msdn.com/efdesign/archive/2009/03/16/foreign-keys-in-the-entity-framework.aspx
http://blogs.msdn.com/efdesign/archive/2008/10/27/foreign-keys-in-the-conceptual-and-object-models.aspx
Defining and Managing Relationship MSDN documentation
Walkthrough:
We’re going to look at the designer experience, the EDMX model differences and a few coding examples. We’ll use this extremely simple database model:
Note the fact that the Posts table has a foreign key to the Blogs table.
Designer Experience
Start by creating a new WPF application then add a new ADO.NET Entity Data Model item to it. Choose to generate the model from the database. Open the Tables portion of the treeview and check the Blogs and Posts tables. Note when choosing the tables with which to generate Entities “Include Foreign Key Columns in the Model” is checked by default. This means new models by default will use the new FK associations rather than Independent Associations. Independent Associations were previously the only type of association offered in the Entity Framework and still can be used. If you want just Independent Associations in your model, you’ll need to uncheck the Include FK Columns in the Model checkbox.
After clicking Finish your model should look as follows:
Double click the association and you’ll see the foreign key properties for the relationship:
Let’s leave this as is for now but note it’s possible to switch an existing Association between an FK or Independent Association type. In this case if you wanted to switch an Association to be Independent, you’d press the Delete button in the Referential Constraint dialog. After doing so you’d need to map the Independent Association appropriately and remove the BlogID property from the Post Entity. For now let’s move on without changing the association type.
For comparison sake, add a new entity to the design surface from the toolbox. Once done, right click on the entity and choose Add->Association:
Note that your association doesn’t have to be an FK association (association types can be mixed in the same model). Uncheck the ‘Add foreign key properties to the ‘Blog’ Entity’ check box then Click OK in the dialog. This will let us later look at the model differences between Independent and Foreign Key associations.
So far we’ve: created a WPF project, added an EDM Data Model to it, reverse engineered our Blogs and Posts tables to the model, then added a third entity and created an Independent Association with it.
XML model differences:
We’re going to briefly diverge and look at some of the differences in the XML generated for the different types of associations in our simple model. If you don’t want to do this, feel free to skip to the next section.
Right click on the EDMX file in your project and choose Open With->XML Editor. This will close the design surface and open the contents of the EDMX file in the XML Editor.
Scrolling down, the CSDL XML fragment for our Independent Association looks like this:
<Association Name="Entity1Blog">
<End Type="BlogsModel.Entity1" Role="Entity1" Multiplicity="1" />
<End Type="BlogsModel.Blog" Role="Blog" Multiplicity="*" />
</Association>
It would also have an MSL XML fragment that tells EF how to traverse the relationship if we’d mapped the new entity & association to storage objects. Since we didn’t complete the mappings the fragment is missing.
The CSDL XML fragment for our FK Associations looks like this:
<Association Name="FK_BlogPost">
<End Role="Blogs" Type="BlogsModel.Blog" Multiplicity="1" />
<End Role="Posts" Type="BlogsModel.Post" Multiplicity="*" />
<ReferentialConstraint>
<Principal Role="Blogs">
<PropertyRef Name="BlogID" />
</Principal>
<Dependent Role="Posts">
<PropertyRef Name="BlogID" />
</Dependent>
</ReferentialConstraint>
</Association>
Notice the ReferentialConstraint element and its contents. There is also no MSL XML fragment for the relationship.
One other thing of interest to note is the Post EntityType has this fragment in the CSDL:
<Property Name="BlogID" Type="Int32" Nullable="false" />
Having the BlogID property on the Post Entity will allow us to directly read & manipulate its value plus use it for data binding (no more need for partial classes with this exposed as a property).
This divergence this tells us three things:
- EF is handling the two different types of Associations completely differently.
- If you want to dig into an EDMX and tell what types of Associations you have you can (but looking at the XML can hurt your eyes J).
- Foreign Key Associations add the parent ID key properties as properties on the child object. This is useful in a number of ways.
Coding experience
Double click on the EDMX file in your project. After clicking Yes, this should reopen the EF Designer for your model. Delete Entity1 from the design surface. This should give you valid model with everything mapped (exactly what you had after running the Add->New Item wizard).
We’re going to run through a few scenarios of how to code against our model. To facilitate, add a button to your WPF form and double click it.
Scenario 1: Adding new Blog and a new Post together by setting Navigation properties.
Note this is what you used to do without FK Associations and is still the recommended way of adding two new dependent objects together. We’ll talk about why in a few minutes. Inside the button event handler add the following code:
using (BlogsEntities ctx = new BlogsEntities())
{
Blog myBlog = new Blog { BlogID = 9, Name = "Tim's blog", Owner = "Tim" };
Post myPost = new Post { PostID = 102, Title = "Post Title", PostContent = "TestContent",
= DateTime.Now, ModifiedDate = DateTime.Now };
//Nav properties will work immediately.
myBlog.Posts.Add(myPost);
ctx.Blogs.AddObject(myBlog);
ctx.SaveChanges();
}
This code opens a connection to the DB, creates a new blog object, creates a new post object, adds the post object to the blog object’s Posts collection, adds the new blog objects to the context, then saves the changes to the database. Note that as soon as we added the myPost object to the Posts collection of myBlog we could use the navigation properties to traverse between the objects.
Scenario 2: Adding new Blog and a new Post together but set the Post BlogID FK property instead of adding to the myBlog Posts collection.
Delete the code you just placed in the event handler and replace it with the following:
using (BlogsEntities ctx = new BlogsEntities())
{
Blog myBlog = new Blog{BlogID = 11, Name = "Tim's blog", Owner = "Tim"};
Post myPost = new Post{PostID = 101,Title = "Post Title", CreatedDate = DateTime.Now,
ModifiedDate = DateTime.Now, PostContent="Post Content", BlogID = 11};
ctx.Posts.AddObject(myPost);
ctx.Blogs.AddObject (myBlog);
ctx.SaveChanges();
}
Note that the navigation properties on the two new objects won’t map to each other until after SaveChanges is called. This is because the context doesn’t know about the parent object yet.
Scenario 3: Adding a new post to an already existing blog.
Replace the code in the event handler with the following:
using (BlogsEntities ctx = new BlogsEntities())
{
Post myPost = new Post {PostID = 102, Title = "Post Title", CreatedDate =
DateTime.Now, ModifiedDate =DateTime.Now, PostContent = "Post Content", BlogID = 11};
//Nav properties will work immediately b/c the Blog object already exists
ctx.Posts.AddObject(myPost);
ctx.SaveChanges();
}
Note we never loaded the Blog object into memory. We knew BlogID 11 was a valid ID and set the post.BlogID property directly. Note also, the navigation property for myPost.Blog will work immediately after setting the FK property because the Blog object already exists in the context. Being able to set the property directly enables some previously difficult data binding scenarios as well as can make some coding experiences easier.
These three coding examples show different ways of creating new objects and setting up their relationships using navigation properties and FK associations.
Summary
In .NET 4.0 we’ve added support for FK Properties and FK Associations to the Entity Framework. It’s still possible to use Independent Associations and the two can be mixed in models. We’re excited to offer FK Associations because they simplify many common Entity Framework coding tasks. Hopefully this walkthrough has given you a feel for how you can use FK Associations and Properties.
As always we'd love to hear your thoughts.
Thanks,
Tim Laverty, Program Manager
-
In a previous post, we walked through the designer’s “out of the box” database schema generation experience. In this post, we show how some new designer features in VS2010 Beta 2 integrate with this capability, then we pop the hood and show how easy it is to replace or extend parts of the generation system.
We will begin with a simple model that contains two newly supported constructs: Employee.EmployerId is a foreign key that references Company.Id, and Person.Address is a complex type.
To show the details of the model, we also include the EDM’s XML:
1: <Schema xmlns:annotation="http://schemas.microsoft.com/ado/2009/02/edm/annotation" Namespace="SimpleModel" Alias="Self" xmlns="http://schemas.microsoft.com/ado/2008/09/edm">
2: <EntityContainer Name="SimpleModelContainer" annotation:LazyLoadingEnabled="true" >
3: <EntitySet Name="Persons" EntityType="SimpleModel.Person" />
4: <EntitySet Name="Companies" EntityType="SimpleModel.Company" />
5: <AssociationSet Name="CompanyEmployee" Association="SimpleModel.CompanyEmployee">
6: <End Role="Company" EntitySet="Companies" />
7: <End Role="Employee" EntitySet="Persons" />
8: </AssociationSet>
9: </EntityContainer>
10: <EntityType Name="Person">
11: <Key>
12: <PropertyRef Name="Id" />
13: </Key>
14: <Property Type="Int32" Name="Id" Nullable="false" annotation:StoreGeneratedPattern="Identity" />
15: <Property Type="String" Name="FirstName" Nullable="false" />
16: <Property Type="String" Name="LastName" Nullable="false" />
17: <Property Name="Address" Type="SimpleModel.Address" Nullable="false" />
18: </EntityType>
19: <EntityType Name="Employee" BaseType="SimpleModel.Person">
20: <Property Type="String" Name="Title" Nullable="false" />
21: <NavigationProperty Name="Company" Relationship="SimpleModel.CompanyEmployee" FromRole="Employee" ToRole="Company" />
22: <Property Type="Int32" Name="EmployerId" Nullable="false" />
23: </EntityType>
24: <EntityType Name="Company">
25: <Key>
26: <PropertyRef Name="Id" />
27: </Key>
28: <Property Type="Int32" Name="Id" Nullable="false" annotation:StoreGeneratedPattern="Identity" />
29: <Property Type="String" Name="Name" Nullable="false" />
30: <Property Type="String" Name="Address" Nullable="false" />
31: <NavigationProperty Name="Employees" Relationship="SimpleModel.CompanyEmployee" FromRole="Company" ToRole="Employee" />
32: </EntityType>
33: <ComplexType Name="Address" >
34: <Property Type="String" Name="Street" Nullable="false" Unicode="true" MaxLength="250" FixedLength="false" />
35: <Property Type="String" Name="City" Nullable="false" Unicode="true" />
36: <Property Type="String" Name="Zip" Nullable="false" FixedLength="true" MaxLength="5" Unicode="false" />
37: <Property Type="String" Name="State" Nullable="true" FixedLength="false" MaxLength="100" Unicode="true" />
38: <Property Type="String" Name="Country" Nullable="false" Unicode="false" />
39: </ComplexType>
40: <Association Name="CompanyEmployee">
41: <End Type="SimpleModel.Company" Role="Company" Multiplicity="1" />
42: <End Type="SimpleModel.Employee" Role="Employee" Multiplicity="*" />
43: <ReferentialConstraint>
44: <Principal Role="Company">
45: <PropertyRef Name="Id" />
46: </Principal>
47: <Dependent Role="Employee">
48: <PropertyRef Name="EmployerId" />
49: </Dependent>
50: </ReferentialConstraint>
51: </Association>
52: </Schema>
Note the ReferentialConstraint element above, which defines the foreign key, and the ComplexType element that defines the Address type.
When we run the database generation script against this model, we get the following table definitions:
-- Creating table 'Persons'
CREATE TABLE [dbo].[Persons] (
[Id] int IDENTITY(1,1) NOT NULL,
[FirstName] nvarchar(max) NOT NULL,
[LastName] nvarchar(max) NOT NULL,
[Address_Street] nvarchar(250) NOT NULL,
[Address_City] nvarchar(max) NOT NULL,
[Address_Zip] char(5) NOT NULL,
[Address_State] nvarchar(100) NULL,
[Address_Country] varchar(max) NOT NULL
);
GO
-- Creating table 'Companies'
CREATE TABLE [dbo].[Companies] (
[Id] int IDENTITY(1,1) NOT NULL,
[Name] nvarchar(max) NOT NULL,
[Address] nvarchar(max) NOT NULL
);
GO
-- Creating table 'Persons_Employee'
CREATE TABLE [dbo].[Persons_Employee] (
[Title] nvarchar(max) NOT NULL,
[EmployerId] int NOT NULL,
[Id] int NOT NULL
);
GO
A few things to note:
- The complex type was “rolled-up” into its owning type’s table, and the name of the complex property was appended to the name of the complex type properties, e.g. “Address_State”.
- The foreign key property “EmployerId” was pulled through into the model, rather than a “hidden” foreign key being generated, as would have been the case for a relationship that did not specify a referential constraint. Another blog post will go into referential constraints in more detail.
- The name of a table that stores instances of subtypes is composed of the name of the subtype’s set to which we append the name of the type, e.g. “Persons_Employee”.
- We’ve set the Address.Zip property to be a fixed length non-unicode string, and so it is generated as a char(5).
- If you do not specify unicode, the default is true. If you do not specify fixed length, the default is false. If you do not specify max length, the default is “max”.
- Property Persons.Id’s StoreGeneratedPattern property is set to “Identity”, which makes it an IDENTITY(1,1) in the database.
- Not shown in the above script are the key and constraint definitions, which are similar to those shown in the previous post.
Now, let’s take a look at how model first actually works, so we can see how to change what it does. Click on any empty area in the designer surface to see the top-level properties of the model:
Of interest to us are two of the three “Database Script Generation” properties:
Database Generation Workflow – Controls the overall process by which the conceptual model is translated into a database script. The default workflow is “TablePerTypeStrategy.xaml”.
DDL Generation Template – Is called by the default database generation workflow to transform the generated database model to DDL. More on this below.
First, let’s take a look at TablePerTypeStrategy.xaml – it is located in Microsoft Visual Studio 10.0\Common7\IDE\Extensions\Microsoft\Entity Framework Tools\DBGen. If we open this file in Visual Studio, we see that it is a Workflow Foundation (WF) workflow:
The first activity, “CsdlToSsdlAndMslActivity” generates the store model (SSDL) for the EDM, and then generates the mappings (MSL) that connect the two. It has the following properties:
The “MslOutputGeneratorType” specifies a class that generates MSL based on a table-per-type mapping strategy. The “OuputGeneratorType” generates SSDL. Rather than replacing this activity and all of the plumbing it provides, you can replace these two classes with your own if you want to change the mapping strategy or otherwise alter the system. In future posts, we will provide examples and more details on the specifics of these classes. You can also replace this entire activity with your own activity that fills the MslOutput and SsdlOutput parameters using any mechanism you wish.
The second activity, “SsdlToDdlActivity” generates DDL from the store model, and it does this by using a T4 template, which makes for very easy customization. In the same folder that TablePerTypeStrategy.xaml is installed, there is also SSDLToSQL10.tt which generates TSQL DDL. Templates for supporting other database platforms will become available in the future from Entity Framework provider writers. T4 templates are simple text files whose intent is to transform some sets of inputs, in this case, SSDL, to some output, DDL in this case. A full description of the template is outside the scope of this post, but we’ll take a brief look at one section of the template, the one that generates the table definitions. To help with readability, we have bolded those parts of the script that generate DDL:
-- --------------------------------------------------
-- Creating all tables
-- --------------------------------------------------
<#
foreach (EntitySet entitySet in Store.GetAllEntitySets())
{
string schemaName = Id(entitySet.GetSchemaName());
string tableName = Id(entitySet.GetTableName());
#>
-- Creating table '<#=tableName#>'
CREATE TABLE <# if (!IsSQLCE) {#>[<#=schemaName#>].<#}#>[<#=tableName#>] (
<#
for (int p = 0; p < entitySet.ElementType.Properties.Count; p++)
{
EdmProperty prop = entitySet.ElementType.Properties[p];
#>
[<#=Id(prop.Name)#>] <#=prop.ToStoreType()#>
<#=WriteIdentity(prop, targetVersion)#> <#=WriteNullable(prop.Nullable)#>
<#=(p < entitySet.ElementType.Properties.Count - 1) ? "," : ""#>
<#
}
#>
);
GO
<#
}
#>
As you can see, the template iterates over the objects in the SSDL and the translation is fairly straightforward.
The experience when additional templates and workflows are installed is tremendously improved relative to Visual Studio 2010 Beta1. To demonstrate this, copy and paste TablePerTypeStrategy.xaml and rename it to CustomStrategy.xaml. Copy and paste SSDLToSQL10.tt and rename it SSDLToCustomDDL.tt. When we switch back to the designer and look at the designer property sheet, we will see these new files appear in the drop downs for the workflow and template properties:
And:
So now you can mix and match two different strategies with two different DDL generators, for example, you could mix and match a table-per-hierarchy strategy with either a SQL or a Firebird database schema template.
But there is a problem: Installing templates and workflows in the Visual Studio path is often neither advisable nor possible. So we’ve provided two additional install locations. The first is %localappdata%\Microsoft\[AppId]\10.0\Extensions\Microsoft\Entity Framework Tools\DBGen where [AppId] depends on your Visual Studio SKU, for example:
D:\documents and settings\sqlcl02\Local Settings\Application Data\Microsoft\VisualStudio\10.0\Extensions\Microsoft\Entity Framework Tools\DBGen.
Copy the same files to this folder and rename them to CustomUserStrategy.xaml and SSDLToCustomUserDDL.tt and they will immediately show up:
Finally, if you want a custom workflow or template specifically for your project, copy the template or workflow to your project and type in the path. For example:
Make sure that the (VS) or (User) postfixes are not in the path.
In summary, it is very easy now to mix and much strategies and target database DDL formats, as well as to install your own custom workflows and templates. In a future post, we will walk through examples of custom strategies and templates.
Noam Ben-Ami
Program Manager,
Entity Designer
-
We’ve released an update of the Entity Framework Feature CTP! The updated CTP includes many requested improvements and added features we’ve gathered from the community since the release of our first CTP and supports installation with Visual Studio 2010 Beta 2 as well. Some of the improvements and added features added since the last CTP include:
- Enhancements to Code Only, including-
- Fine Grained Control over model
- Specify Navigation Property Inverses
- Specify Property Facets
- Complex Types
- Customizable Mappings
- Change Table Name, Column Names
- Specify Custom Inheritance Strategy
- Entity Splitting
- Join Table Mapping
- The Self-Tracking Entities template, allowing code generation of EF entities that facilitate ease of use in WCF/N-Tier scenarios-
- Foreign Key associations: Self-Tracking Entities can take advantage of the Foreign Keys in the Model feature added in .NET 4.0 Beta 2 and can contain both navigation properties and Foreign Key properties for the same association. Fix-up logic has been tidied up to be aware of FKs.
- Support for Silverlight 3: Generated entity types can be compiled to target Silverlight 3 and can be used in combination with Silverlight-enabled WCF services.
- Databinding support: Generated entity types now implement INotifyPropertyChanged and use ObservableCollections allowing them to work better with WPF and Silverlight databinding.
- Richer concurrency control support: Self-Tracking Entities now support the same variations for optimistic concurrency control as the Entity Framework. Original values are preserved for all required properties according to their concurrency mode in the Entity Data Model.
- Improved independent association support: The approach for managing entities with dangling references has been reengineered to avoid unnecessary database round-trips.
- New and improved methods: AcceptChanges, StartTracking, StopTracking where added and the existing MarkAsX methods are now extension methods.
- Generated code improvements and refactoring: The ApplyChanges implementation has been moved to the Context template so the template has no binary dependencies besides Entity Framework. Generated code for entity types have been refactored.
Over the next few weeks we’ll be posting walkthroughs that dive deeper into each feature. We also have a few features we plan to release in CTP format in the next few months including an updated POCO code gen template. Your comments and feedback are most welcome; please give us your comments here, our design blog, through Connect or through the ADO.NET Entity Framework pre-release forums. Please stay tuned for more news!
Thanks!
The Entity Framework Team