Step 5 - Examining the Generated Code
Examining the Generated Business Objects
In the Solution Explorer, click the Order.cs file to open it in the code editing window. Your source code should look something like this:
namespace Acme.OrderSystem.BusinessCF { /// <summary> /// Summary description for Order. /// </summary> public partial class Order : ABusinessObject<OrderEntity> { #region Association Properties /// <summary> /// Business Entity object /// </summary> public override OrderEntity Entity { get { if (this._entity == null) { this._entity = this.CreateEntityObject(); } return this._entity; } set { this._entity = value; } } private OrderEntity _entity; /// <summary> /// Business Rule object /// </summary> public virtual OrderRules Rules { get { return (OrderRules)this.BusinessRuleObj; } set { this.BusinessRuleObj = value; } } #endregion /// <summary> /// Constructor /// </summary> public Order() { this.EntityFramework = true; this.TableName = "Orders"; this.PhysicalDbcObjectName = "dbo.Orders"; this.PrimaryKey = "OrderID"; this.HookConstructor(); this.EntityCentric = true; } /// <summary> /// Factory method that creates a business rule object /// </summary> /// <returns>Reference to the business rule object</returns> protected override mmBusinessRule CreateBusinessRuleObject() { return new OrderRules(this); } /// <summary> /// Set default values on the new entity /// </summary> /// <param name="entity">New Entity</param> protected override void HookSetDefaultValues(OrderEntity entity) { // Store the hard-coded default values via the entity object if (entity != null) { entity.Freight = 0; } } } }
Things to note:
- The namespace of the Order business object (Acme.OrderSystem.BusinessCF) is the default namespace you specified when first creating the project.
- The name of the business class (Order) is what you specified in the MM .NET Business Layer Generator.
- The base class of the Order business object is ABusinessObject.
- If you expand the Association Properties region by clicking on the + sign to its right you can see association properties have been created for the associated Entity and Rules objects. You can also view the contents of a collapsed region by simply hovering your mouse pointer over it.
- The first line of constructor code sets the EntityFramework property to true, indicating that by default, the business controller object works with Entity Framework entities.
- The second line of constructor code stores the value "Orders" in the business object's TableName property. In a pure Entity Framework implementation, this property is not used. In mixed-mode implementations where you use both the Entity Framework along with classic MM .NET entity objects, this property specifies the default table name when the business object retrieves data into an ADO.NET DataSet.
- The fourth line of constructor code stores the value "OrderID" into the object's PrimaryKey property. In a pure Entity Framework implementation, this property is not used. In mixed-mode implemetations where you use both the Entity Framework along with classic MM .NET entity objects, this property specifies which column in the associated DataTable holds the primary key. It was automatically derived by the Business Layer Generator from the Northwind database.
- CreateBusinessRuleObject() is a factory method used at run time to instantiate the OrderRules object.
- The HookSetDefaultValues() method is called on a new entity when you run the business object's CreateEntity() method. It stores a zero (0) default value to the entity's Freight property just as specified in the Business Layer Generator.
Examining the Generated Entities
Now, let's take a look at some of the generated entities.- In the Solution Explorer, select the OrderEntity.cs file, to see the generated code:
[Table("Orders")] public partial class OrderEntity : ABusinessEntity { [Key] public int OrderID { get; set; } [Column(TypeName = "nchar")] [ForeignKey("Customer")] [Required] [StringLength(5)] [Index("CustomerID")] [Index("CustomersOrders")] public string CustomerID { get; set; } [ForeignKey("Employee")] [Index("EmployeeID")] [Index("EmployeesOrders")] public int? EmployeeID { get; set; } [Index("OrderDate")] public DateTime? OrderDate { get; set; } public DateTime? RequiredDate { get; set; } [Index("ShippedDate")] public DateTime? ShippedDate { get; set; } [ForeignKey("Shipper")] [Index("ShippersOrders")] public int? ShipVia { get; set; } public decimal? Freight { get; set; } [Required] [StringLength(40)] public string ShipName { get; set; } [StringLength(60)] public string ShipAddress { get; set; } [StringLength(15)] public string ShipCity { get; set; } [StringLength(15)] public string ShipRegion { get; set; } [StringLength(10)] [Index("ShipPostalCode")] public string ShipPostalCode { get; set; } [StringLength(15)] public string ShipCountry { get; set; } // Relationships public virtual CustomerEntity Customer { get; set; } public virtual EmployeeEntity Employee { get; set; } public virtual ShipperEntity Shipper { get; set; } }
A few things to note:
- At the top of the class, the [Table("Orders"] annotation specifies the name of the associated table. When forward engineering, EF will create a table in the database named Orders from this entity.
- The [Key] annotation specifies OrderID is the primary key.
Note: Entity Framework Code First requires that every table has a primary key! - The [Column(TypeName = "nchar")] and [StringLength(5)] annotations on the CustomerID property specify that the corresponding table column is nchar(5). Properties only need a TypeName annotation when the specific type can't be derived from the type of the entity property.
- The [ForeignKey("Customer")] annotation on the CustomerID property indicates it is a foreign key, and the associated navigation property is called Customer, which you can see at the bottom of the class declaration:
// Relationships public virtual CustomerEntity Customer { get; set; } public virtual EmployeeEntity Employee { get; set; } public virtual ShipperEntity Shipper { get; set; }
- The [Required] annotation indicates the CustomerID and ShipName are required values.
- The [Index("CustomerID")] and [Index("CustomersOrders")] annotations indicate there are CustomerID and CustomerOrders indexes on the corresponding table column.
- Next, in the Solution Explorer, select the OrderDetailEntity.cs file to see the generated code:
[Table("OrderDetails")] public partial class OrderDetailEntity : ABusinessEntity { [Key, Column(Order = 1)] public int OrderID { get; set; } [Key, Column(Order = 2)] public int ProductID { get; set; } [Required] public decimal UnitPrice { get; set; } [Required] public Int16 Quantity { get; set; } [Required] public Single Discount { get; set; } }
Because the OrderDetails table has a composite primary key, there are [Key, Column(Order = 1)] and [Key, Column(Order = 2)] annotations on the OrderID and ProductID properties, indicating the order of the key columns.
- In the Solution Explorer, selection the RegionEntity.cs file to see the generated code. Notice the [Key] annotation on the RegionID property:
[Table("Region")] public partial class RegionEntity : ABusinessEntity { [Key] public int RegionID { get; set; } [Column(TypeName = "nchar")] [Required] [StringLength(50)] public string RegionDescription { get; set; } }
With this in mind, in the Solution Explorer, click on the EntityDataModelContainer.cs file, and check out the OnModelCreating() method:
/// <summary> /// OnModelCreating method /// </summary> /// <param name="modelBuilder"></param> protected override void OnModelCreating(DbModelBuilder modelBuilder) { // Remove the following line of code if you want to generate index on FKs modelBuilder.Conventions.Remove<ForeignKeyIndexConvention>(); modelBuilder.Entity<RegionEntity>().HasKey(e => e.RegionID, config => config.IsClustered(false)); base.OnModelCreating(modelBuilder); }
This method is called at run time the first time an instance is created from the EntityDataModelContainer class. It provides a place for you to add code that further configures the Entity Data Model.
Notice the following line of code in particular:
modelBuilder.Entity<RegionEntity>().HasKey(e => e.RegionID, config => config.IsClustered(false));
Why is this line of code here? It's because primary keys (such as RegionID) are clustered by default. If you have a key that is non-clustered, you can't use annotations to specify that. You must use Fluent API to do it instead. This line of code specifies RegionID is a non-clustered primary key.
Examining the DbSets
In addition to generating individual entities for each table, the MM .NET BLG also adds DbSet properties to your project's DbContext.
- In the Solution Explorer, select the EntityDataModelContainer.cs file.
- Notice the DbSet properties at the top of the class file. One property is created for each table, and is used to retrieve entities of that type from the database:
public partial class EntityDataModelContainer : DbContext { #region ObjectSet Properties /// <summary> /// SupplierEntities DbSet /// </summary> public virtual DbSet<SupplierEntity> SupplierEntities { get; set; } /// <summary> /// ShipperEntities DbSet /// </summary> public virtual DbSet<ShipperEntity> ShipperEntities { get; set; } /// <summary> /// RegionEntities DbSet /// </summary> public virtual DbSet<RegionEntity> RegionEntities { get; set; } /// <summary> /// ProductEntities DbSet /// </summary> public virtual DbSet<ProductEntity> ProductEntities { get; set; } /// <summary> /// OrderEntities DbSet /// </summary> public virtual DbSet<OrderEntity> OrderEntities { get; set; } /// <summary> /// OrderDetailEntities DbSet /// </summary> public virtual DbSet<OrderDetailEntity> OrderDetailEntities { get; set; }
See Also:
Step 7 - Updating the Database
© (c) 2026 Oak Leaf Enterprises, Inc., 1996-2026 • Updated: 02/12/26
Comment or report problem with topic
