Object Identity (LINQ to SQL)

Objects in the runtime have unique identities. Two variables that refer to the same object actually refer to the same instance of the object. Because of this fact, changes that you make by way of a path through one variable are immediately visible through the other.

Rows in a relational database table do not have unique identities. Because each row has a unique primary key, no two rows share the same key value. However, this fact constrains only the contents of the database table.

In reality, data is most often brought out of the database and into a different tier, where an application works with it. This is the model that LINQ to SQL supports. When data is brought out of the database as rows, you have no expectation that two rows that represent the same data actually correspond to the same row instances. If you query for a specific customer two times, you get two rows of data. Each row contains the same information.

With objects you expect something very different. You expect that if you ask the DataContext for the same information repeatedly, it will in fact give you the same object instance. You expect this behavior because objects have special meaning for your application and you expect them to behave like objects. You designed them as hierarchies or graphs. You expect to retrieve them as such and not to receive multitudes of replicated instances just because you asked for the same thing more than one time.

In LINQ to SQL, the DataContext manages object identity. Whenever you retrieve a new row from the database, the row is logged in an identity table by its primary key, and a new object is created. Whenever you retrieve that same row, the original object instance is handed back to the application. In this manner the DataContext translates the concept of identity as seen by the database (that is, primary keys) into the concept of identity seen by the language (that is, instances). The application only sees the object in the state that it was first retrieved. The new data, if different, is discarded.

LINQ to SQL uses this approach to manage the integrity of local objects in order to support optimistic updates. Because the only changes that occur after the object is at first created are those made by the application, the intent of the application is clear. If changes by an outside party have occurred in the interim, they are identified at the time SubmitChanges() is called.

Note

If the object requested by the query is easily identifiable as one already retrieved, no query is executed. The identity table acts as a cache of all previously retrieved objects.

Examples

Object Caching Example 1

In this example, if you execute the same query two times, you receive a reference to the same object in memory every time.

Dim cust1 As Customer = _
    (From cust In db.Customers _
    Where cust.CustomerID = "BONAP" _
    Select cust).First()

Dim cust2 As Customer = _
    (From cust In db.Customers _
    Where cust.CustomerID = "BONAP" _
    Select cust).First()
Customer cust1 =
    (from cust in db.Customers
     where cust.CustomerID == "BONAP" 
     select cust).First();

Customer cust2 =
    (from cust in db.Customers
     where cust.CustomerID == "BONAP" 
     select cust).First();

Object Caching Example 2

In this example, if you execute different queries that return the same row from the database, you receive a reference to the same object in memory every time.

Dim cust1 As Customer = _
    (From cust In db.Customers _
    Where cust.CustomerID = "BONAP" _
    Select cust).First()

Dim cust2 As Customer = _
    (From ord In db.Orders _
    Where ord.Customer.CustomerID = "BONAP" _
    Select ord).First().Customer
Customer cust1 =
    (from cust in db.Customers
     where cust.CustomerID == "BONAP" 
     select cust).First();

Customer cust2 =
    (from ord in db.Orders
     where ord.Customer.CustomerID == "BONAP" 
     select ord).First().Customer;

See Also

Other Resources

Background Information (LINQ to SQL)