次の方法で共有


Entity Services, Metadata & Mapping

Part of the Entity Framework FAQ .

13. EDM

13.1.Does Entity Framework support Abstract types in EDM models?

In Entity Framework it is possible to declare Abstract types in EDM model (csdl file) — i.e. no entity instances can be created for these types, but types can be derived from them. In fact, types can be marked as abstract in the designer. The runtime even allows abstract types to be the base type for multiple different entitysets (imagine a scenario where you want a single base type for all your entities even though they live in multiple sets), but this is not supported in the designer (at least for v1). For more information, see Abstract Type (EntityType Element CSDL).

13.2.Does Entity Framework have support for Complex types? What are Complex types? How are they different from Entity Types in the EDM?

Complex type is the Entity Framework name for value properties which have more intricate structure than scalars. The canonical example is an Address type which contains several parts (street, city, state, etc.) Complex types are somewhat like entities except that they do not have any identity of their own (they are value types). This means that a complex type instance is always a part of some other enclosing entity—it can’t stand on its own, it doesn’t have relationships, etc. Entity Framework support Complex types but in first release, the mapping scenarios for complex types are significantly limited: inheritance is not supported (inheritance definitely is supported for entities—just not complex types), complex type properties cannot be null and they can only occur in single instances, not collections. Also, complex types are not supported in the designer. For more information, see Complex Type (EDM).

13.3.Does Entity Framework support multiple entity sets per type? Why is "multiple entity sets per type" support required?

Entity Framework supports multiple entity sets per type -- this means you can define a model which has more than one entity set with the same base type. This is important because it enables models which work more naturally with various database models. If you have two tables with the same schema (say "accounts" and "expired_accounts" or something), then you can define entitysets for each of them which use the same entity type rather than needing to create a different entity type which just happens to have all the same properties. This resulted in a change to a number of the object context APIs -- strongly typed contexts, for instance, now have AddToEntitySetName methods (where EntitySetName is the actual name of each entity set). For more information, see Entity Sets (EDM).

13.4.Are associations between sub-types supported?

Entity Framework supports associations between sub-types. The association between sub types allows you to define relationships between any types in the type hierarchy even if they aren't the base types. So, for instance, if I have a hierarchy that has Customer and BigAccountCustomer, then I could create an entity type DiscountPolicy and a relationship that only relates BigAccountCustomers to DiscountPolicies not just regular customers.

13.5.Does the EDM support guids?

Yes.  The EDM supports guid as one of its primitive types.  You can use guids as regular columns or as primary keys in your conceptual model.  See question in later section about EntityKey for more information on using guids in EntityKeys.

13.6.Does the EDM/EF support enums?

No.  In v1 of the EF, you cannot create a conceptual model which has a property of type enum and map it to a column in your database.  There have been a number of requests for this feature, and it is certainly something which will be worked on in future releases. 

One partial workaround: If you have a string or integer column in your database, you can map it to a property in your entity and set the getter and setter access level to be private (either by writing your classes by hand or by modifying those properties in the designer so the generated code makes them private).  Then you can create a second property in the partial class of your generated entities (or in the main file if you are writing by hand) which does the translation between the value from the database and an enum.  This will work for basic programming patterns, but you won’t be able to query by the enum directly in LINQ and some other scenarios may also be limited.

Object Services will enforce model directives like cascade delete *for the subset of the model that has been loaded into memory*.  This doesn’t mean, though, that you have to load everything in memory.  What it means is that you need to setup your database so that it will enforce the same constraints for that portion of the model that hasn’t been loaded.

Cascade delete in the conceptual model helps your object graphs stay consistent.  Cascade delete in the database helps your database stay consistent.  You should implement both or neither. For more information, see Referential Constraints (Entity Framework).

14. Mapping

14.1.Can stored procedures return polymorphic results?

Yes stored procedures that retrieve entity instances can return polymorphic results rather than being restricted only to results of a single type.

14.2.How can I map a stored procedure? 

The EF mapping system supports mapping stored procedures for all four CRUD (Create, Read, Update and Delete) operations. For more details and a full example of reading entities from a sproc, see:

· <blogs.msdn.com/adonet/archive/2007/09/14/how-to-map-stored-procedures-using-the-ado-net-entity-framework.aspx>

· How to: Define a Model with a Stored Procedure (Entity Framework)

· How to: Execute a Query Using a Stored Procedure (Entity Framework)

For details and an example of creating, updating and deleting entities from a sproc, see:

· <blogs.msdn.com/adonet/archive/2007/03/08/using-stored-procedures-for-change-processing-in-the-ado-net-entity-framework.aspx>

· Stored Procedure Support (Entity Framework) 

14.3.How to map read-only Entities? How to use Defining QueryViews in mapping files?

One way to map read-only entities is to use a Defining Query. See <blogs.msdn.com/dsimmons/archive/2007/11/08/mapping-read-only-entities.aspx> and QueryView Element (EntitySetMapping) for more details.

14.4.How can I use stored procedures that only return simple types?

In v1 the EF only supports read sprocs which return entities. In v2 we plan to add support for sprocs which return collections of scalars or of complex types, but we haven’t yet decided whether or not the EF will support sprocs which return single scalars. In any case, though, you can always use classic ADO.Net to accomplish those tasks, and since the EF exposes the underlying database connection, it’s relatively straightforward to integrate this kind of code with other EF-based code. This process is made even simpler with the addition of the EFExtensions library which can be found at: code.msdn.microsoft.com/EFExtensions. With the EFExtensions library you could add a partial method to your context which would call your stored procedure with code that looks something like this:

public int callMySproc()

{

    DbCommand command = this.CreateStoreCommand("MySproc", CommandType.StoredProcedure);

    int result;

    using (this.Connection.CreateConnectionScope())

    {

        result = command.ExecuteNonQuery();

    }

    return result;

}

15. Metadata

15.1.Does the Entity Framework allow embedding metadata files as resources in the assembly?

Yes Entity Framework allows storing metadata files as resources in the assembly; in the connection string you can tell the Entity Framework to find them there. The way to do this is to add the CSDL, MSL and SSDL files to your project and set the "Build Action" property on each one to "Embedded Resource". Then when you specify your connection string, rather than explicitly listing the metadata files, you can just add "metadata=res://*/;" which tells the EF to look for appropriate resources in your apps statically linked assemblies any that it finds. For more information, see Connection Strings (Entity Framework).

The only thing to be careful about is that the assembly that has the resources should be loaded in the same app domain that has the entity connection.

15.2.When is EDMX file used? What is the difference between EDMX file and the three schema files (CSDL, MSL and SSDL)?

The EDM designer uses a file called EDMX to store all of the metadata about an Entity Framework model. This one file includes the CSDL, MSL and SSDL just in separate sections within it. When it comes to runtime, the system requires the three separate files, and the designer projects automatically create them in the application out directory.

15.3.How is the "using" support in metadata files used?

<Using> support in metadata files: Models can be built from multiple separate CSDL files—somewhat like a “using” statement in a C# file which brings a namespace into the file or a #include statement in a C/C++ program except with greater validation than you get in the purely textual preprocessing of #include. For more information, see Using Element (CSDL).

15.4.Can we add custom annotations in the CSDL file?

There is a support in CSDL files to include custom annotations which the framework ignores but can be useful for tools or other systems built around the EDM. These annotations are surfaced in the metadata APIs but not otherwise used by the EF.

16. EntityClient

16.1.How are connection strings managed in the Entity Framework? How can I create a connection string at runtime?

When you use the designer or EdmGen.exe to generate classes from your model, part of what gets generated is a strongly-typed ObjectContext which provides a convenient façade for working with your model. Part of the standard pattern is that the connection string which was originally used to access the database in order to generate the model is embedded in an EntityClient connection string which is placed into the app.config file under the same name as your entity container (specified in the CSDL and used as the name of the strongly-typed ObjectContext type in the generated code). If the app.config file exists and has a connection string whose name matches the container, then the generated classes have a nice, parameterless constructor which will automatically pick up that connection string and use it.

This mechanism is great for many scenarios--it makes for nice clean code, and it follows a great best-practice of putting the connection string out into the config file where it's easier to swap out in situations like where you might use one connection string for development, another for testing/staging and a third for final deployment. That said, there are cases where you might want to more dynamically generate the connection string--for example have multiple database servers for different environments and wanted to provide the user with the opportunity to specify the server as well as credential information at runtime. So, it's important to understand what the parts of the connection string are and how they go together.

If you create a connection string at runtime, then it's still quite straightforward to use. Instead of using the parameterless constructor for the strongly-typed context, you can just use the constructor overload which takes a connection string. This connection string is the exact same connection string that you use either with an ObjectContext (the base type or one of the strongly typed classes that inherit from it) or directly with EntityClient. It follows the same model as all other connection strings which is a set of name value pairs separated by semi-colons, and it has three parts:

1. A specification for where to find the metadata (csdl, msl & ssdl) which EntityClient will use for mapping between the conceptual model and the database. The keyword for this section is “metadata=”, and there are several different kinds of values you can give it. I mentioned the one I use most often above which is just to specify that the metadata lives in resources within the assembly and that the system should look through all the resources looking for appropriate ones. You can do this with “metadata=res://*/;”, or you can specify a pipe delimited list of directories or files (either absolute or relative to your app directory) which contain the metadata.

2. The name of the database provider which EntityClient should use to actually talk to the database. For example, “Provider=System.Data.SqlClient;”.

3. The connection string that you would use with the database provider to access your database. Since this value itself has a series of keywords separated by semi-colons, the string is just enclosed in double quotes. In my sample model it looks like this, “provider connection string="MultipleActiveResultSets=true;database=dpmr;server=.;Integrated Security=true;".

If you are going to build up these parts dynamically, then naturally the recommended way to do so is using a connection string builder, and EntityConnectionBuilder makes this easy. For the provider connection string, you can of course do a similar thing using something like SqlConnectionBuilder. So, the whole thing together would look like this:

SqlConnectionStringBuilder sqlBuilder = new SqlConnectionStringBuilder();

sqlBuilder.MultipleActiveResultSets = true;

sqlBuilder.DataSource = ".";

sqlBuilder.InitialCatalog = "dpmr";

sqlBuilder.IntegratedSecurity = true;

 

EntityConnectionStringBuilder entityBuilder = new EntityConnectionStringBuilder();

entityBuilder.ProviderConnectionString = sqlBuilder.ToString();

entityBuilder.Metadata = "res://*/";

entityBuilder.Provider = "System.Data.SqlClient";

 

For more information, see Connection Strings (Entity Framework).

16.2.Can I access the underlying store connection given an EntityConnection?

Given an EntityConnection you can easily access the store connection, which makes it much easier to go around the covers if you need to. However in reality you don't need to as Entity Framework is designed to cover most of the scenarios required for app building through its public API. For more information, see Managing Connections in Object Services (Entity Framework).

17. EntityKey

17.1.Does the Entity Framework support server-generated key values? 

Yes! The flow of a typical new entity with a server-generated key value looks something like this:

1. Construct the entity instance. At this point the key properties all have default values (null or 0).

2. Add the instance to your context. A temporary key is created and used to store the entity in the ObjectStateManager.

3. Call SaveChanges on the context. The EntityAdapter computes a SQL insert statement (or a stored proc invocation if so-specified in the mapping) and executes it.

4. EntityAdapter writes the server-generated value back to the ObjectStateEntry for the entity. This assumes, of course, that the insert succeeded and that the SSDL was properly configured to indicate that there is a server generated value. Fortunately, if the SSDL is generated from the database schema by a tool, this configuration is automatically done as part of that generation.

5. The ObjectStateEntry pushes the server-generated value into the entity itself. The EntityAdapter is written to operate solely at the conceptual model layer and uses the DataRecord interface on the ObjectStateEntry to read and write values from the entity. The ObjectStateEntry guarantees that the entity object and the DataRecord interface always contain the same data (for current values the DataRecord, in fact, is virtualized over the entity rather than storing its own copy of the data).

6. When AcceptChanges is called on the ObjectStateEntry, a permanent EntityKey is computed using the new, unique property key values. The ObjectStateManager then does an internal fixup replacing all instances of the temporary key with the new permanent key.

To configure the EF for a server-generated key value, you just need the StoreGeneratedPattern attribute to be set on the database column in the SSDL. For a key it should typically set to “Identity” which means the value will be generated when the row is inserted but then not change after that. For other server-generated properties you might want to use the value “Computed” which means that it will change every time the row is updated.

In a word, yes. You can create arbitrarily complex graphs of entities with server generated values and the system can handle inserts of those entire graphs in a single call to SaveChanges.

17.3.Can you use a guid property as part of an entity key?

Yes.  You can use a guid in your conceptual model as a regular property or a primary key.

There is, however, a limitation that the EF does not support primary keys whose type is binary.  What this means in practice is that if your database has a column of type "uniqueidentifier", then the automatic model generation will recognize that it contains a guid and configure the corresponding property in the conceptual model to be a guid making everything happy, but if your column in the database is of type binary with a length of 16 bytes, then the automatic model generation will make the type of the property in the conceptual model a byte array of length 16, and that cannot be the primary key for your entity. 

If you go into the designer, you can manually modify the type of the conceptual model property to be a guid rather than a byte array, and then the property can be the entity key for that type.  At that point, you will receive errors from the mapping system saying that it can't map a guid onto a 16 byte binary.  To fix that you will need to open the EDMX file in the XML editor (or edit your SSDL file if you are not using the designer) and change the metadata for the column in your database to claim that it is really a uniqueidentifier rather than a 16 byte binary.  Once all of this is done, you will fool the EF into thinking that the column is a uniqueidentifier which maps nicely to a guid, and everything should be happy.

17.4.Can I use a server-generated guid as my entity key?

Unfortunately, in v1 of the EF this is not supported.  While it is possible with SQL Server to have a column of type “uniqueidentifier” and to set it’s default value to be “newid()”, with SQL Server 2000 there’s no good way to extract the value that the server generated at the time you do the insert.  This can be done on more recent versions of SQL Server, though, so the intent is that we should find a clean way to special case this support in future versions of the EF so it can be supported on those databases that allow it and not on others.  For now, the work around is to generate the guid on the client (ideally in the constructor of your object) rather than on the server.

17.5.If I use guids for my keys, can I generate them on the client rather than the server?

Yes you can.  There is one thing to keep in mind, though: The default GUID generation scheme creates GUIDs which can make for very inefficient indexes in the database.  Wherever possible I would recommend using a server generated integer or something like that for the key properties of an entity.

 

Comments