Chapter 8. LINQ to Entities: Advanced Concepts and Features

In the previous chapter, we learned some basic concepts and features of LINQ to Entities such as querying and updating database tables and views and changing loading behaviors by using the Include method.

In this chapter, we will learn some advanced features of LINQ to Entities such as stored procedure support, concurrency control, and transactional processing. After this chapter, we will rewrite the data access layer of our WCF service to utilize LINQ to Entities technology.

In this chapter we will cover:

  • Calling a stored procedure
  • Inheritance support
  • Concurrency control
  • Transaction support

Calling a stored procedure

Calling a stored procedure is different from calling a table or a view because a stored procedure can't be called directly. A function import has to be added for the stored procedure and its result set has to be mapped. The modeling of a stored procedure is also different from modeling a table or view. In the following sections, we will learn how to call a simple stored procedure, how to map the returned result of a stored procedure to an entity class, and how to create a new entity for the result set.

We will re-use the same application that we used in the previous chapter and add more methods to the program.

Mapping a stored procedure to a new entity class

First, we will try to call a simple stored procedure. In the sample database, there is a stored procedure called Ten Most Expensive Products. We will call this stored procedure to get the top ten most expensive products.

Modeling a stored procedure

Before we can call this stored procedure we need to model it. Perform the following steps:

  1. Open the Northwind.edmx designer.
  2. Right-click on an empty space of the designer surface and select Update Model from Database…:
    Modeling a stored procedure
  3. From the Update Wizard window, on the Choose Your Database Objects and Settings page, make sure the Add tab is selected, and then expand the dbo node under Stored Procedures and Functions, and check Ten Most Expensive Products.
  4. Make sure the Import selected stored procedures and functions into the entity model option is checked.
  5. Click on the Finish button.
    Modeling a stored procedure

After you save the Northwind.edmx diagram, it will add the Ten_Most_Expensive_Products method to the NorthwindEntities class and add a new class Ten_Most_Expensive_Products_Result as the result datatype of the stored procedure.

Querying a stored procedure

Now, from Program.cs, we can call this stored procedure as follows:

var tenProducts = from p in 
    NWEntities.Ten_Most_Expensive_Products()
    select p;
foreach (var p in tenProducts)
{
    Console.WriteLine("Product Name: {0}, Price: {1}",
    p.TenMostExpensiveProducts, p.UnitPrice);
}

As we know the return result of the stored procedure, we can also replace the var datatype with the specific return type, as shown in the following code snippet:

IEnumerable<Ten_Most_Expensive_Products_Result> tenProducts = 
    from p 
    in NWEntities.Ten_Most_Expensive_Products()
    select p;
foreach (Ten_Most_Expensive_Products_Result p in tenProducts)
{
    Console.WriteLine("Product Name: {0}, Price; {1}",
    p.TenMostExpensiveProducts, p.UnitPrice);
}

In this way, we can clearly see the datatype of the tenProducts variable, so later on we can compare this query with the one that maps to an existing entity class.

The SQL statement is pretty straightforward, as follows:

exec [dbo].[Ten Most Expensive Products]

The output will look like the one shown in the following screenshot:

Querying a stored procedure

Mapping a stored procedure to an existing entity class

In the above example, LINQ to Entities created a new type for the return result of the stored procedure. It actually just added the word Result after the stored procedure name to create the name of the return datatype. If we know that the return result is a kind of entity, we can tell LINQ to Entities to use that specific entity as the return type instead of creating a new type.

For example, let's create a stored procedure as follows:

Create PROCEDURE [dbo].[GetProduct]
   (
   @ProductID int
   )
AS
   SET NOCOUNT ON
   Select * from Products where ProductID = @ProductID

You can create this stored procedure in Microsoft SQL Server Management Studio or by right-clicking on the Stored Procedures node in Server Explorer of Visual Studio and selecting Data Connections | Northwind.dbo | Add New Stored Procedure from the context menu.

After the stored procedure has been created, follow these steps to add it to the entity data model and add a function import:

  1. Open the Northwind.edmx designer.
  2. Right-click on an empty space of the designer surface and select Update Model from Database….
  3. From the Update Wizard window, on the Choose Your Database Objects and Settings page, make sure the Add tab is selected, and then expand the dbo node under Stored Procedures and Functions, and check GetProduct.
  4. This time make sure the Import selected stored procedures and functions into the entity model option is not checked.
  5. Click on the Finish button.
  6. As we didn't check the option Import selected stored procedures and functions into the entity model, the stored procedure has not been imported to the entity model for us. The reason is we don't want to create a new result type for this stored procedure; instead, we will map this stored procedure to an existing entity as described in the following steps.
  7. On the designer surface, right-click on an empty space and select Add New from the context menu, and then select Function Import….
    Mapping a stored procedure to an existing entity class
  8. In the Add Function Import window, type GetProduct in the Function Import Name field and select GetProduct as the stored procedure name from the drop-down list.
  9. Select Entities as Returns a Collection Of and choose Product as the entity from the drop-down list.
    Mapping a stored procedure to an existing entity class
  10. Click on the OK button.
  11. Click on the Save button to save the model so the new function for the new stored procedure can be created in the context class.
  12. Now LINQ to Entities will use the Product class as the return type of this stored procedure.

To call this method you can write a statement as follows:

Product getProduct = NWEntities.GetProduct(1).FirstOrDefault();

The complete method for the stored procedure should be as follows:

static void TestStoredProcedure()
{
using(NorthwindEntities NWEntities = new NorthwindEntities())
  {
    IEnumerable<Ten_Most_Expensive_Products_Result> tenProducts =
              from p
              in NWEntities.Ten_Most_Expensive_Products()
              select p;
    Console.WriteLine("Ten Most Expensive Products:");
    foreach (Ten_Most_Expensive_Products_Result p in tenProducts)
    {
      Console.WriteLine("Product Name: {0}, Price; {1}",
                 p.TenMostExpensiveProducts, p.UnitPrice);
    }

    // map a stored procedure to an entity class
  Product getProduct = NWEntities.GetProduct(1).FirstOrDefault();
  Console.WriteLine("
Product name for product 1:{0}", 
    getProduct.ProductName);
  }
}

And if you run the program, you should have an output as shown in the following screenshot:

Mapping a stored procedure to an existing entity class

Interestingly, you can add another function for the same stored procedure but with a different function name (GetProduct1), and for the new function, you can check the Complex radio button to create a new type (GetProduct1_Result) for the result of the stored procedure instead of using the Product class. LINQ to Entities will automatically create a new class for the return type.

The generated return type class GetProduct1_Result is almost identical to the Product class.

A big difference between the GetProduct and GetProduct1 methods is that the product you retrieved using GetProduct is managed by the DbContext entity. Any changes you made to it will be committed back to the database if you call SaveChanges() later. However, the product you retrieved using GetProduct1 is not managed by the DbContext entity, and thus won't be committed back to the database if you call SaveChanges() later.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset