Attaching and Detaching Objects
This article is relevant to entity models that utilize the deprecated Visual Studio integration of Telerik Data Access. The current documentation of the Data Access framework is available here.
In Telerik Data Access, objects can be attached to or detached from a context. Objects that are attached to a context are tracked and managed by that context. Detached objects are not referenced by the context. This topic describes how to attach and detach object and some considerations for doing so:
Detaching Objects
In Telerik Data Access application, you can detach objects from the context. To do this, call the CreateDetachedCopy method.
The CreateDetachedCopy method returns a copy of the real object.
There are several overloads of the CreateDetachedCopy method:
- CreateDetachedCopy<T>(T entity) - does a flat detach of a single entity without considering any reference fields. If any reference properties are loaded beforehand, they are ignored during the detached operation. All reference collections will be empty and the reference properties will be null.
- CreateDetachedCopy<T>(T entity, params string[] referenceProperties) - does a flat detach of a single entity and includes the reference properties specified as a string.
- CreateDetachedCopy<T>(T entity, params System.Linq.Expressions.Expression<Func<T,object>>[] referenceProperties) - creates a flat detach of a single entity including all the references specified by a lambda expression.
- CreateDetachedCopy<T>(T entities, FetchStrategy fetchStrategy) - creates and returns a detached copy of the persistent capable object that loads all the fields in accordance to the given fetch strategy.
-
CreateDetachedCopy<T>(IEnumerable<T> entities, FetchStrategy fetchStrategy) - does a flat detach of an entity collection and includes the references specified by the fetch plan. If you pass Null for fetch strategy, Telerik Data Access will use the default strategy of the context. Note that the references will be loaded per type and not per instance. This means that if the fetch plan specifies that all employees (from the Northwind database) will be loaded with their reference employees and orders this will result in the following properties being populated:
- ReportsTo of the main employee. ReportsTo of the referenced employee and so on until the max depth of the fetch plan is reached.
- Orders of the main employee as well as all the orders of its reference employee (ReportsTo property).
The following example shows how to detach a Car object along with the referenced Category and RentalOrders.
public void DetachObjectGraph(EntitiesModel dbContext)
{
Car carToDetach = dbContext.Cars.FirstOrDefault();
Car detachedCopy = dbContext.
CreateDetachedCopy(carToDetach, car => car.Category, car => car.RentalOrders);
}
Public Sub DetachObjectGraph(ByVal dbContext As EntitiesModel)
Dim carToDetach As Car = dbContext.Cars.FirstOrDefault()
Dim detachedCopy As Car = dbContext. _
CreateDetachedCopy(carToDetach, Function(car) car.Category, Function(car) car.RentalOrders)
End Sub
The following example demonstrates how to detach a collection of Employee objects along with the referenced Orders.
public void DetachObjectGraph( EntitiesModel dbContext )
{
FetchStrategy fetchStrategy = new FetchStrategy();
fetchStrategy.LoadWith<Employee>( e => e.Orders );
List<Employee> employees = dbContext.Employees.ToList();
var detachedEmployees = dbContext.CreateDetachedCopy<Employee>( employees, fetchStrategy );
}
Public Sub DetachObjectGraph(ByVal dbContext As EntitiesModel)
Dim _fetchStrategy As New FetchStrategy()
_fetchStrategy.LoadWith(Of Employee)(Function(e) e.Orders)
Dim employees As List(Of Employee) = dbContext.Employees.ToList()
Dim detachedEmployees = dbContext.CreateDetachedCopy(Of Employee)(employees, _fetchStrategy)
End Sub
Considerations for Detaching Objects
The following considerations apply when detaching objects:
-
By default detach only affects the specific object passed to the CreateDetachedCopy method. If the object being detached has related objects in the context, those objects are not detached. This is a flat detach. When there is no fetch strategies defined, Telerik Data Access uses the default fetch plan to figure out which entities and properties should be detached. The "default" fetch strategy tells the OpenAccessContext to retrieve all the value fields of an object and only the ID's of the reference ones.
In the following example, a Car object is detached from the context. However, a FetchStrategy is not specified. That means that the referenced Category object will not be detached, i.e. the detachedCar.Category property will be null. Only the CategoryID property will be initialized.using ( EntitiesModel dbContext = new EntitiesModel() ) { Car detachedCar = dbContext.CreateDetachedCopy( dbContext.Cars.FirstOrDefault() ); Debug.Assert( detachedCar.Category == null ); }
Using dbContext As New EntitiesModel() Dim detachedCar As Car = dbContext.CreateDetachedCopy(dbContext.Cars.FirstOrDefault()) Debug.Assert(detachedCar.Category Is Nothing) End Using
If you want to detach an object with any reference fields, you have to explicitly specify them.
Attaching Objects
When a query is executed inside a context instance, the returned objects are automatically attached to that context. You can also attach objects to a context that are obtained from a source other than a query. You might attach objects that have been previously detached, or objects that have been retrieved outside the OpenAccessContext. You can also attach objects that have been stored in the view state of an ASP.NET Web Application or have been returned from a Web Service.
The following example adds a collection of detached Car objects to a detached Category object and then attaches this object graph to the context.
public void AttachObjectGraph(EntitiesModel dbContext, Category detachedCategory,
IEnumerable<Car> detachedCars)
{
// Define the relationships.
foreach (Car car in detachedCars)
{
detachedCategory.Cars.Add(car);
}
// Attach the object graph to the context.
dbContext.AttachCopy(detachedCategory);
}
Public Sub AttachObjectGraph(ByVal dbContext As EntitiesModel, _
ByVal detachedCategory As Category, ByVal detachedCars As IEnumerable(Of Car))
' Define the relationships.
For Each _car As Car In detachedCars
detachedCategory.Cars.Add(_car)
Next _car
' Attach the object graph to the context.
dbContext.AttachCopy(detachedCategory)
End Sub
Considerations for Attaching Objects
The following considerations apply when attaching objects to the context:
- If the object being attached has related objects, those objects are also attached to the context.
Accessing Detached Object State
The OpenAccessContext exposes a static property that provides status information for both attached and detached objects.
ObjectState state = OpenAccessContext.PersistenceState.GetState(car);
Dim state As ObjectState = OpenAccessContext.PersistenceState.GetState(car)
The above example will return the object state of a given object. Note that the result for the attached objects will be the same as the one achieved via the context.GetState instance method. The result will differ only for detached objects where you could get the following values:
- DetachedNew - object is detached and was marked as to be inserted.
- DetachedDirty - object is detached and was modified and needs to be updated.
- DetachedClean - object is detached and was not modified.
Another useful method is IsDetached. It returns true if a given entity is detached from a context.
Getting Original Values
Telerik Data Access allows you to get the original property values for a tracked domain model entity. The original values are usually the entity's property values as they were before any changes. The original property values could be obtained by using the generic OpenAccessContext.GetOriginalValue<T> method. The method accepts two parameters. The first one is the object that holds the property or field of interest. The second parameter is a string containing the name of the property for which you want to retrieve the original value. Once you call the SaveChanges method, the original property value will be replaced with the one that you have already committed to the database. For more information, please refer to Accessing Original Values After Changes.