How to: Manage One-to-Many Associations
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.
Suppose, you have the following domain model (it is based on the SofiaCarRental database). The model includes two entities related with a one-to-many association. The Car entity has one instance of Category. You can use the Car.Category property to access the Category instance that is associated with an instance of the Car entity. The Category entity has many instances of Car. You can use the Category.Cars property to access the Car instances that are associated with an instance of the Category entity.
In this scenario, by default the value of IsManaged for both navigation properties is False and additionally, the property itself for Car.Category is disabled.
Below you can find how to insert update and delete objects from domain entities related through a one-to-many association:
IsManaged notifies Telerik Data Access whether to populate the foreign key column of the child table in the database with the appropriate value when a new child object is added to the collection navigation property of a parent object. Since Car.Category is not a collection, IsManaged is disabled.
Additionally, depending on the configuration of the association, the IsManaged property can have the following values:
Source Property | Target Property | |||
Value | Disabled | Value | Disabled | |
Both ends exist | false | yes | false | no |
Source End only | - | - | false | yes |
Target End only | false | yes | - | - |
Insert Related Objects
In case you need to insert a new category with a related car, you can do it like this:
-
Set the IsManaged property of the Category.Cars collection to True in the Properties window and save the model.
-
Here is a complete code snippet showing you how to set a new relation by using the collection property. Note that it is recommended to add the new objects to the context first, and then set the relation through the collection property. The final step is to invoke the SaveChanges() method.
using (EntitiesModel dbContext = new EntitiesModel()) { Car newCar = new Car(); newCar.Make = "Audi"; newCar.Model = "A8"; Category newCategory = new Category(); newCategory.CategoryName = "MyCategory"; dbContext.Add(newCategory); newCategory.Cars.Add(newCar); dbContext.SaveChanges(); }
Using dbContext As New EntitiesModel() Dim newCar As New Car() newCar.Make = "Audi" newCar.Model = "A8" Dim newCategory As New Category() newCategory.CategoryName = "MyCategory" dbContext.Add(newCategory) newCategory.Cars.Add(newCar) dbContext.SaveChanges() End Using
If you don't set the IsManaged property to True, you may persist two new records in the database, respectively in the Cars and Categories tables without relating them (the car.CategoryId column allows NULL values) or get an exception (the car.CategoryId column does not allow NULL values).
Note that in this case only the newCategory is added to the context and newCar is added to the navigation property. After the call to the SaveChanges() method both objects are saved in the database keeping the relationship between them. This is called persistence by reachability, which means that if you build a graph of related objects, adding the top most one to the context will cause the context to track the rest too.
For general information about inserting objects you can check the How to: Insert Objects article.
Delete Related Objects
In case you need to delete a category from Categories (the parent table), you need to make sure that the corresponding objects in Cars is removed first. For example:
using (EntitiesModel dbContext = new EntitiesModel())
{
Category someCategory = dbContext.Categories.FirstOrDefault();
dbContext.Delete(someCategory.Cars);
dbContext.Delete(someCategory);
dbContext.SaveChanges();
}
Using dbContext As New EntitiesModel()
Dim someCategory As Category = dbContext.Categories.FirstOrDefault()
dbContext.Delete(someCategory.Cars)
dbContext.Delete(someCategory)
dbContext.SaveChanges()
End Using
If the cars are not removed prior to the removal of the category you will experience DataStoreException: The DELETE statement conflicted with the REFERENCE constraint.
In case you need to remove only the cars about a given category, you can pass someCategory.Cars to the Delete() method of the context and then call SaveChanges().
For general information about deleting objects you can check the How to: Delete Objects article.
Update Related Objects
In case you need to change the category a given car belongs to, you need to make sure that IsManaged is True for the Category.Cars navigation property and simply move the car from the collection of the first category to the collection of the second category. For example:
using (EntitiesModel dbContext = new EntitiesModel())
{
Category someCategory = dbContext.Categories.
FirstOrDefault(sc => sc.CategoryID == 1);
Category otherCategory = dbContext.Categories.
FirstOrDefault(sc => sc.CategoryID == 2);
Car someCar = dbContext.Cars.
FirstOrDefault(sc => sc.CategoryID == someCategory.CategoryID);
someCategory.Cars.Remove(someCar);
otherCategory.Cars.Add(someCar);
dbContext.SaveChanges();
}
Using dbContext As New EntitiesModel()
Dim someCategory As Category = dbContext.Categories. _
FirstOrDefault(Function(sc) sc.CategoryID = 1)
Dim otherCategory As Category = dbContext.Categories. _
FirstOrDefault(Function(sc) sc.CategoryID = 2)
Dim someCar As Car = dbContext.Cars. _
FirstOrDefault(Function(sc) sc.CategoryID = someCategory.CategoryID)
someCategory.Cars.Remove(someCar)
otherCategory.Cars.Add(someCar)
dbContext.SaveChanges()
End Using
Removing a car object from the collection of given category will not remove it from the database. It will only set car.CategoryID to NULL, if the column allows NULL values.
For general information about updating objects you can check the How to: Update Objects article.