This approach has been available since the first version of Entity Framework. In this approach, we start with an already existing database and start creating our EDM from the existing database. Let's try to see how this works using the Entity Framework Database First approach with our ToDo sample. To use the Entity Framework Database First approach, we have to add a new ADO.NET EDM to our project:
Let's start by defining a database for the ToDo application. Let's create a simple table that will keep a track of all the ToDo items:
The application requirements state that it should be possible to perform the following activities on the ToDos:
Read the list of ToDos
Create a ToDo item
Read a specific ToDo item
Update the status of a ToDo item
Delete a ToDo item
When we add the EDM, it asks us whether we want to create the conceptual model from the existing database, or if we want to create an empty model. For the Database First approach, we need to select an existing database. The following screenshot shows the wizard step that asks you to select the database:
Once we choose to add the EDM, we need to specify the database that should be used to create it. So, the next step in the wizard will ask you for the connection to the database. Let's see what this wizard step looks like:
Once the connection is successfully established, the wizard shows us all the tables, views, procedures, and functions that we will want to access from our application. Using this wizard, we can also choose to include the foreign key relations in our conceptual model and singularization of the model name, in case the table name is plural in our conceptual model:
Once the conceptual model is created, the EDM will be created for use in our application. The application will create a .EDMX
file that contains all the information about our conceptual entity model and its mapping to the database tables:
We can modify the conceptual model and change the mapping using entity designer. Let's try to change the property ToDo1
to ToDoItem
in our conceptual model. Note that only the class property has been changed, and not the column name:
If we open the EDMX file, we can find the following three sections:
Conceptual schema definition: This specifies how a strongly typed model for our conceptual model will be created:
<edmx:ConceptualModels> <Schema Namespace="ToDoDBModel" Alias="Self" annotation:UseStrongSpatialTypes="false" xmlns:annotation="http://schemas.microsoft.com/ado/2009/02/edm/annotation" xmlns="http://schemas.microsoft.com/ado/2009/11/edm"> <EntityType Name="ToDo"> <Key> <PropertyRef Name="Id" /> </Key> <Property Name="Id" Type="Int32" Nullable="false" /> <Property Name="TodoItem" Type="String" MaxLength="Max" FixedLength="false" Unicode="true" Nullable="false" /> <Property Name="IsDone" Type="Boolean" Nullable="false" /> </EntityType> <EntityContainer Name="ToDoDBEntities" annotation:LazyLoadingEnabled="true"> <EntitySet Name="ToDos" EntityType="Self.ToDo" /> </EntityContainer> </Schema> </edmx:ConceptualModels>
Storage schema definition: This specifies how the storage model is created, that is, how the values are stored in the database:
<edmx:StorageModels> <Schema Namespace="ToDoDBModel.Store" Provider="System.Data.SqlClient" ProviderManifestToken="2012" Alias="Self" xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" xmlns="http://schemas.microsoft.com/ado/2009/11/edm/ssdl"> <EntityType Name="ToDos"> <Key> <PropertyRef Name="Id" /> </Key> <Property Name="Id" Type="int" Nullable="false" /> <Property Name="Todo" Type="nvarchar(max)" Nullable="false" /> <Property Name="IsDone" Type="bit" Nullable="false" /> </EntityType> <EntityContainer Name="ToDoDBModelStoreContainer"> <EntitySet Name="ToDos" EntityType="Self.ToDos" Schema="dbo" store:Type="Tables" /> </EntityContainer> </Schema> </edmx:StorageModels>
Mapping: This specifies the mapping between the conceptual model and the storage model:
<edmx:Mappings> <Mapping Space="C-S" xmlns="http://schemas.microsoft.com/ado/2009/11/mapping/cs"> <EntityContainerMapping StorageEntityContainer="ToDoDBModelStoreContainer" CdmEntityContainer="ToDoDBEntities"> <EntitySetMapping Name="ToDos"> <EntityTypeMapping TypeName="ToDoDBModel.ToDo"> <MappingFragment StoreEntitySet="ToDos"> <ScalarProperty Name="Id" ColumnName="Id" /> <ScalarProperty Name="TodoItem" ColumnName="Todo" /> <ScalarProperty Name="IsDone" ColumnName="IsDone" /> </MappingFragment> </EntityTypeMapping> </EntitySetMapping> </EntityContainerMapping> </Mapping> </edmx:Mappings>
Tip
We should always prefer to change these values from the Visual Entity Designer. We can modify this XML manually to change it as per our needs, but Visual Entity Designer allows us to perform most of the modifications, and unless we need to make a change that is not supported by entity designer, we should try not to make them manually.
Once the EDM is created, we will get a class generated for each model object present in our conceptual model. We will also get the DBContext
class that will let's use these strongly typed models:
The generated DBContext
class will look like this:
public partial class ToDoDBEntities : DbContext { public ToDoDBEntities() : base("name=ToDoDBEntities") { } public virtual DbSet<ToDo> ToDos { get; set; } }
The generated model class will look like this:
public partial class ToDo { public int Id { get; set; } public string TodoItem { get; set; } public bool IsDone { get; set; } }
Now we are ready to write typed queries against the generated conceptual model, and Entity Framework will execute our queries on the database, and return the results in the form of these strongly typed models. Creating new data or updating the existing data is also very easy, because Entity Framework automatically tracks the changes we make in our models, and lets us save the changes to the database. This can simply be done by calling the SaveChanges
method on the DBContext
class. One important thing to note here is that the read operation can utilize Language-Integrated
Query (LINQ) to query the object data model, and Entity Framework will take care of converting it to the appropriate SQL query and retrieve the results.
If our application is a data-centric application, and all we need is to be able to perform CRUD operations using strongly typed objects, this is all that we are going to need. However, one of the great benefits of Entity Framework is being able to modify the conceptual models to better adapt to our domain needs, and then use the mappings to map the domain model to the database tables. We can have relationships between our domain models and still let them persist the data in a given set of tables.
Tip
In the Database First approach, the Entity Model is able to incrementally update the conceptual model if the database schema is updated. We just need to right-click on the visual designer and chose Update Model from Database.
In the later chapters, we will see how to manage multiple models, how we can define relationships between the entities, introduce inheritance hierarchies, customize entities, and much more. This will give you a good foundation to get started with the Entity Framework Database First approach if you haven't used it before, and will refresh your memory if you have.