How to: Customize Generated Data Objects (Entity Framework)

This topic shows how to add a custom method to a generated data class. The examples in this topic are based on the Adventure Works Sales Model. To run the code in this example, you must have already added the AdventureWorks Sales Model to your project and configured your project to use the Entity Framework. To do this, complete the procedures in How to: Manually Configure an Entity Framework Project and How to: Manually Define an Entity Data Model (Entity Framework).

Example

This example defines a custom UpdateOrderTotal method for the generated SalesOrderHeader class. This custom method updates the TotalDue property based on the current values of the tax, freight, and individual item totals. This method is defined as a partial class so that it is not lost when the SalesOrderHeader class is regenerated by the Entity Framework tools.

Partial Public Class SalesOrderHeader
    ' Update the order total.
    Public Sub UpdateOrderTotal()

        Dim newSubTotal As Decimal = 0

        ' Ideally, this information is available in the EDM.
        Dim taxRatePercent As Decimal = GetCurrentTaxRate()
        Dim freightPercent As Decimal = GetCurrentFreight()

        ' If the items for this order are loaded or if the order is 
        ' newly added, then recalculate the subtotal as it may have changed.
        If (Me.SalesOrderDetail.IsLoaded Or _
            Me.EntityState = Data.EntityState.Added) Then

            Dim item As SalesOrderDetail
            For Each item In Me.SalesOrderDetail
                ' Calculate line totals for loaded items.
                newSubTotal += (item.OrderQty * _
                    (item.UnitPrice - item.UnitPriceDiscount))
            Next
            Me.SubTotal = newSubTotal
        End If

        ' Calculate the new tax amount.
        Me.TaxAmt = Me.SubTotal _
             + Decimal.Round((Me.SubTotal * taxRatePercent / 100), 4)

        ' Calculate the new freight amount.
        Me.Freight = Me.SubTotal _
            + Decimal.Round((Me.SubTotal * freightPercent / 100), 4)

        ' Calculate the new total.
        Me.TotalDue = Me.SubTotal + Me.TaxAmt + Me.Freight

    End Sub
End Class
public partial class SalesOrderHeader
{
    // Update the order total.
    public void UpdateOrderTotal()
    {
        decimal newSubTotal = 0;

        // Ideally, this information is available in the EDM.
        decimal taxRatePercent = GetCurrentTaxRate();
        decimal freightPercent = GetCurrentFreight();

        // If the items for this order are loaded or if the order is 
        // newly added, then recalculate the subtotal as it may have changed.
        if (SalesOrderDetail.IsLoaded ||
            EntityState == EntityState.Added)
        {
            foreach (SalesOrderDetail item in this.SalesOrderDetail)
            {
                // Calculate line totals for loaded items.
                newSubTotal += (item.OrderQty *
                    (item.UnitPrice - item.UnitPriceDiscount));
            }

            this.SubTotal = newSubTotal;
        }

        // Calculate the new tax amount.
        this.TaxAmt = this.SubTotal
             + Decimal.Round((this.SubTotal * taxRatePercent / 100), 4);

        // Calculate the new freight amount.
        this.Freight = this.SubTotal
            + Decimal.Round((this.SubTotal * freightPercent / 100), 4);

        // Calculate the new total.
        this.TotalDue = this.SubTotal + this.TaxAmt + this.Freight;
    }
}

This example modifies an order and then calls the custom UpdateOrderTotal method on SalesOrderHeader to update the TotalDue property. Because TotalDue has the StoreGeneratedPattern="computed" attribute applied in the store schema definition language (SSDL) file, this updated value is not saved to the server when SaveChanges is called. Without this attribute, an UpdateException occurs if you attempt to update a computed column on the server.

Dim orderId = 43662

Using context As New AdventureWorksEntities
    Try
        ' Return an order and its items.
        Dim order As SalesOrderHeader = _
        context.SalesOrderHeader() _
        .Include("SalesOrderDetail") _
        .Where("it.SalesOrderID = @orderId", _
               New ObjectParameter("orderId", orderId)).First()

        Console.WriteLine("The original order total was: " _
            & order.TotalDue.ToString())

        ' Update the order status.
        order.Status = 1

        ' Increase the quantity of the first item, if one exists.
        If order.SalesOrderDetail.Count > 0 Then
            order.SalesOrderDetail.First().OrderQty += Convert.ToInt16(1)
        End If
        ' Increase the shipping amount by 10%.
        order.Freight = _
            Decimal.Round(order.Freight * Convert.ToDecimal(1.1), 4)

        ' Call the custom method to update the total.
        order.UpdateOrderTotal()

        Console.WriteLine("The calculated order total is: " _
            & order.TotalDue.ToString())

        ' Save changes in the object context to the database.
        context.SaveChanges()

        ' Refresh the order to get the computed total from the store.
        context.Refresh(RefreshMode.StoreWins, order)

        Console.WriteLine("The store generated order total is: " _
            & order.TotalDue.ToString())
    Catch ex As InvalidOperationException
        Console.WriteLine(ex.ToString())
    Catch ex As UpdateException
        Console.WriteLine(ex.ToString())
    End Try
End Using
int orderId = 43662;

using (AdventureWorksEntities context =
    new AdventureWorksEntities())
{
    try
    {
        // Return an order and its items.
        SalesOrderHeader order =
            context.SalesOrderHeader
            .Include("SalesOrderDetail")
            .Where("it.SalesOrderID = @orderId", 
               new ObjectParameter("orderId", orderId)).First();

        Console.WriteLine("The original order total was: "
            + order.TotalDue);

        // Update the order status.
        order.Status = 1;

        // Increase the quantity of the first item, if one exists.
        if (order.SalesOrderDetail.Count > 0)
        {
            order.SalesOrderDetail.First().OrderQty += 1;
        }

        // Increase the shipping amount by 10%.
        order.Freight = 
            Decimal.Round(order.Freight * (decimal)1.1, 4);

        // Call the custom method to update the total.
        order.UpdateOrderTotal();
        
        Console.WriteLine("The calculated order total is: "
            + order.TotalDue);

        // Save changes in the object context to the database.
        int changes = context.SaveChanges();

        // Refresh the order to get the computed total from the store.
        context.Refresh(RefreshMode.StoreWins, order);

        Console.WriteLine("The store generated order total is: "
            + order.TotalDue);
    }
    catch (InvalidOperationException ex)
    {
        Console.WriteLine(ex.ToString());
    }
    catch (UpdateException ex)
    {
        Console.WriteLine(ex.GetType().ToString() +": " + ex.ToString());
    }
}

See Also

Concepts

Customizing Objects (Entity Framework)

Other Resources

Working with Custom Objects (Entity Framework Tasks)