Entity Framework 6 Recipes Chinese translation series (38), entityframework
For the original intention of translation and why I chose Entity Framework 6 Recipes, see Chapter 7 use object service in the beginning of this series.
This chapter provides a practical solution to common problems in real applications. The applications we build should be able to accept changes in the deployment environment. We can make the applications flexible enough to make them almost unconfigured and require hard coding.
The first three sections provide you with solutions to these challenges. The remaining sections cover the use of the edmgen.exe utility, the use of the Identity relationship, and the retrieval of objects from the ObjectContext.
7-1 dynamically build a connection string
Problem
You want to dynamically build a connection string for your application.
Solution
Many real applications are initially stored on the developer's computer and then tested in one or more tests, integration tests, and staging environments, is released as a product. You want to dynamically configure the application connection string based on the current environment.
Dynamically build a connection string for your application as shown in code listing 7-1.
Code List 7-1.Dynamically build a connection string
Public static class ConnectionStringManager {public static string EFConnection = GetConnection (); private static string GetConnection () {var sqlBuilder = new SqlConnectionStringBuilder (); sqlBuilder. dataSource = ConfigurationManager. appsetdatasource ["SqlDataSource"]; // fill in the remaining sqlBuilder. initialCatalog = ConfigurationManager. appsetalog ["SqlInitialCatalog"]; sqlBuilder. integratedSecurity = true; sqlBuilder. multipleActiveResultSets = true; var eBuilder = new EntityConnectionStringBuilder (); eBuilder. provider = "System. data. sqlClient "; eBuilder. metadata = "res: // */Recipe1.csdl | res: // */Recipe1.ssdl | res: // */Recipe1.msl"; eBuilder. providerConnectionString = sqlBuilder. toString (); return eBuilder. toString () ;}} public partial class EF6RecipesContainer {public EF6RecipesContainer (string nameOrConnectionString): base (nameOrConnectionString ){}}
Principle
When you add an ADO. NET object data model to your project, the object framework adds an entry in the <ConnectionStirngs> section of the. config file of the project. At runtime, input the key of the configuration entry to the constructor of the context object (the most common section in this book uses the context EF6RecipesContext ). With the given key, the database context searches for the connection string in the. config file and uses it.
To dynamically create a connection string based on the environment where the application is located, we have created the ConnectionStringManager class (for example, code listing 7-1 ). In the GetConnection () method, we obtain the data source and initial catalog of the specific environment from the configuration file. In order to use ConnectionStringManager, an additional constructor is added to the EF6RecipesContainer class, which accepts a parameter indicating the connection string or connection string name.
When EF6RecipesContainer is instantiated, we pass ConnectionStringManager. EFContection to it as a parameter. Eventually, it uses a dynamically created connection string to connect to the database service.
7-1 read the model from the database
Problem
You want to read the CSDL, MSL, and SSDL defined for the model from the data table.
Solution
Suppose you have a model 7-1.
Figure 7-1. A model containing the Cutomer entity
Our model has only one entity: Customer. Concept layer CSDL), msl of the ing layer and SSDL of the storage layer. Their definitions can usually be found in the. edmx file in your project. But we want to read their definitions from the database. To read these definitions from the database, follow these steps:
1. Right-click the designer to view the attributes. Change the code generation policy to None. We will use POCO for our Customer class;
2. Create a table 7-2. This table will save the definition of our project model;
Figure 7-2. The table Definitions stores the Definitions of SSDL, CSDL, and MSL. Note that the field type is XML.
3. Right-click the designer to view the attributes. Change the metadata project Processing (Metadate Artifact Processing) to "Copy to Output Directory ). Recompile your project. The compilation process generates three files in the output directory: Recipe2.ssdl, Recipe2.csdl, and Recipe2.msl;
4. Insert the content of the file generated in the previous step to the appropriate column in the Definitions table. The Id column uses the value 1;
5. Use code listing 7-2 to read metadata from the database table Definitions and create a MetadateWorkSpace class to be used by the application;
Code List 7-2.Read data from Table Definitions
public static class Recipe2Program { public static void Run() { using (var context = ContextFactory.CreateContext()) { context.Customers.AddObject( new Customer { Name = "Jill Nickels" }); context.Customers.AddObject( new Customer { Name = "Robert Cole" }); context.SaveChanges(); } using (var context = ContextFactory.CreateContext()) { Console.WriteLine("Customers"); Console.WriteLine("---------"); foreach (var customer in context.Customers) { Console.WriteLine("{0}", customer.Name); } } } } public class Customer { public virtual int CustomerId { get; set; } public virtual string Name { get; set; } } public class EFRecipesEntities : ObjectContext { private ObjectSet<Customer> customers; public EFRecipesEntities(EntityConnection cn) : base(cn) { } public ObjectSet<Customer> Customers { get { return customers ?? (customers = CreateObjectSet<Customer>()); } } } public static class ContextFactory { static string connString = @"Data Source=localhost; initial catalog=EFRecipes;Integrated Security=True;"; private static MetadataWorkspace workspace = CreateWorkSpace(); public static EFRecipesEntities CreateContext() { var conn = new EntityConnection(workspace, new SqlConnection(connString)); return new EFRecipesEntities(conn); } private static MetadataWorkspace CreateWorkSpace() { string sql = @"select csdl,msl,ssdl from Chapter7.Definitions"; XmlReader csdlReader = null; XmlReader mslReader = null; XmlReader ssdlReader = null; using (var cn = new SqlConnection(connString)) { using (var cmd = new SqlCommand(sql, cn)) { cn.Open(); var reader = cmd.ExecuteReader(); if (reader.Read()) { csdlReader = reader.GetSqlXml(0).CreateReader(); mslReader = reader.GetSqlXml(1).CreateReader(); ssdlReader = reader.GetSqlXml(2).CreateReader(); } } } var edmCollection = new EdmItemCollection(new XmlReader[] { csdlReader }); var ssdlCollection = new StoreItemCollection(new XmlReader[] { ssdlReader }); var mappingCollection = new StorageMappingItemCollection( edmCollection, ssdlCollection, new XmlReader[] { mslReader }); var localWorkspace = new MetadataWorkspace(); localWorkspace.RegisterItemCollection(edmCollection); localWorkspace.RegisterItemCollection(ssdlCollection); localWorkspace.RegisterItemCollection(mappingCollection); return localWorkspace; } }
The output of code list 7-2 is as follows:
Customers---------Jill NickelsRobert Cole
Principle
The first part of the code list 7-2 should be very familiar to you. We use the object framework to create a new context object, create some object objects, and call the SaveChages () method to persist these object to the database. To obtain these entities, we enumerate the entire set and output them from the console. The only difference is that we call ContextFactory. CreateConext () when creating a context object (). Generally, we only need to use the new operator to obtain a new EFRecipesEntities context object instance.
We create a ContextFacotry and use the stored metadata to create our context object. The metadata is not stored in the. edmx file, but in the database. We use the CreateContext () method to implement this function. The CreateContext () method creates a new EntityConnection based on two parameters: the workspace we created in the CreateWorkSpace () method, and an SQL connection string. Real work occurs when the CreateWorkSpace () method creates a workspace.
The CreateWorkSpace () method opens the connection to the storage metadata database. We construct an SQL statement to read a row of data from the Definitions table, which is saved in the Definitions table (7-2, definition of concept layer, storage layer, and ing layer. We use Xmlreaders to read these definitions. With the definition data, we can create the Instance Object of MetadataWorkspace. MetadataWorkspace represents a model in memory. Generally, this workspace is created from the. edmx file by default pipe of the object framework, but now we create from the database table Definitions. There are other ways to create this object, including using embedded resources and Code First.
Code List 7-2 uses POCO to represent the Customer entity. Although we only cover the content of POCO in chapter 8, here We Use POCO to simplify the code. With POCO, we don't need to use classes generated by the Entity Framework. Instead, we use a self-created class that does not depend on the object framework. In code list 7-2, we use the Customer class to define the Customer entity. At the same time, we have created our own context object EFRecipesEntities. Of course, our context object depends on the object framework because it inherits from ObjectContext.
Entity Framework exchange QQ group: 458326058. You are welcome to join us.
Thank you for your continued attention, my blog address: http://www.cnblogs.com/VolcanoCloud/