While Microsoft’s Partial Classes and Partial Methods let you extend the classes generated for you by Entity Framework, in the end you’re working with someone else’s code (albeit, code that is, effectively, written for you by the ADO.NET team). But with Entity Framework 4.1‘s code-first technology you can write your own classes and have EF use them. You’re still able to use LINQ to retrieve your data and EF to save your changes. To use EF’s code-first technology, after downloading EF 4.1 and creating your project in Visual Studio, just add references to the EntityFramework, System.ComponentModel.DataAnnotations and System.Data.Entit libraries.
For this example, I’ll use the Northwind database because it demonstrates some of the typical issues you’ll encounter in integrating your code with an existing database using EF’s code-first technology. I’ll start by creating a Products class to represent a row in the Products table and include a few properties that correspond to the columns in the table:
Public Class Products Public Property ProductID As Integer Public Property ProductName As String Public Property CategoryID As Integer End Class
EF will, by default, tie this class and its properties to the Products table with its columns by matching their respective names. However, I’ll now end up with a pluralized class name (Products) representing a single row in the table. I’d rather have a singular name for this class. I can change the name of my class and still tie it to the Products table by using the DataAnnotations Table attribute:
<System.ComponentModel.DataAnnotations.Table("Products")> Public Class Product
I also need to tell EF which of these columns is the table’s primary key field by adding the Key annotation to my ProductID property:
<System.ComponentModel.DataAnnotations.Key()> Public Property ProductID As Integer
My next step is to create the OrderDetails class to represent a row in the Order Details table. The Table attribute lets me not only singularize the name of the object but deal with the unfortunate space in the name of the Order Details table which I can’t match in my class name:
<System.ComponentModel.DataAnnotations.Table("Order Details")> Public Class OrderDetail Public Property OrderId As Integer Public Property ProductId As Integer Public Property UnitPrice As Decimal Public Property Quantity As Int16 End Class
The OrderDetail table has a composite key made up the OrderId and ProductId columns. Both of the matching properties need to be marked with the Key attribute. They also need to have the Column attribute added to specify the order that the two columns appear in the key:
<System.ComponentModel.DataAnnotations.Key()> <System.ComponentModel.DataAnnotations.Column(Order:=0)> Public Property OrderId As Integer <System.ComponentModel.DataAnnotations.Key()> <System.ComponentModel.DataAnnotations.Column(Order:=1)> Public Property ProductId As Integer
My final change is to tie these two classes together in a way that mimics the foreign key/primary key relationship between the two tables in the database. To the OrderDetail class, I add a property to the OrderDetails class that points to the product that the OrderDetail is tied. As required by code-first, mark it as Overridable. The name of the property doesn’t matter here but its return type must point to the class that represents the related table:
Public Overridable Property Product As Product
In the Product class, I need a similar property that points to the multiple Order Details rows that a Product may appear on. That means that I need to declare the OrderDetails property as some object that implements the ICollection interface. Again, the property must be marked as Overridable and the datatype of the return value must be the related class:
Public Overridable Property OrderDetails As ICollection(Of OrderDetail)
Other than adding the annotations, this is the same code you’d write if you were creating your own business entities. The next step is to create the factory class that will retrieve rows from the database and create these objects and put in some business code of my own.