ObjectContext Handles Updating
How was it possible to save all of the changes with one simple command? The NWEntities class that you instantiated is not just a wrapper class for the entities. If you look at the class file that Visual Studio generated from the .csdl
file, you can see that the NWEntities class inherits from System.Data.Objects.ObjectContext. System.Data.Objects represents the Object Services API and is part of the ADO.NET Entity Framework. ObjectContext is the real workhorse behind much of what you can do with the ADO.NET Entity Framework and Object Services.
In the case of the NWEntities class, in its role as an ObjectContext, you can see that it manages the entities (Customers, Employees, etc.). Not only does it hand you these entities when you ask for them, but it keeps track of anything that is done to the entities. Therefore, while the user of the application is making changes to the data in the grid, the grid is communicating all of the changes made to each of the entities in the list back to the mother ship, NWEntities. ObjectContext.SaveChanges will then coordinate sending all of the changes (adds, updates, and deletes) back to the database.
Another important aspect of querying against the ADO.NET Entity Framework is deferred loading
. At some point, the ObjectContext must actually retrieve the data from the database. By default, this happens at the first point that your code explicitly needs the data. In the dbDataRecord
sample, that will happen when you call For Each dbrec in custs
. This becomes more important when you are dealing with related data, which you'll see more about later in this article. If you are using SQL Server, you can open up SQLProfiler and see exactly when the call is made into the database.
Loading Objects and Their Children
|At some point, the ObjectContext must actually retrieve the data from the database. By default, this happens at the first point that your code explicitly needs the data.|
Because the conceptual layer is aware of the relations between data, related objects come along for free. When you request Customers, you also have access to the Customer's orders. Orders, in turn, provide Employees (the salesperson), Shippers, Customers, and Order Details. However, when requesting an Order, you may not necessarily want all that related data to come along; if it did, it would be a waste of resources. To prevent this, the default behavior for ADO.NET Entity Framework is to use deferred loading (also called lazy loading
). This means that the Framework will not load the related data until you explicitly ask for it using a simple Load
method. The following example iterates through the Customers, and then through the orders for each customer.
Dim custs = NWEntities.Customers
For Each cust As Customers In custs
For Each o In cust.Orders
Debug.WriteLine(" " & o.OrderDate.ToString)
Prior to calling cust.Orders.Load
is Null. To access the orders, you need to explicitly Load them. Because Orders is a property collection of Customers, this is called collection navigation
Note that it is necessary to use MARS (Multiple Active Result Sets) in order for this to work. MARS allows you to use a single connection to return multiple results. Add the parameter MultipleActiveResultSets=True
to the connection string in the app.config
Going in the other direction, you can get the Customer object information for an Order:
Dim ords = NWEntities.Orders
For Each o As Orders In ords
For Each c As Customers In o.CustomersReference
Debug.WriteLine(" " & c.CompanyName)
Notice the use of o.CustomersReference.Load
, rather than o.Customers.Load
. Customers is not a collection of objects within an order. Instead, the order has a reference to the related customer entity; this is called reference navigation
It is possible to override this behavior using the ObjectQuery.Include
modifier when referencing or querying the entity. For example, the following line of code would result in Orders coming along with each Customer entity: