Modifying an entity instance
Modifying an entity's data (the entity instance) can be done in multiple ways:
- Loading an existing entity in memory, alter one or more fields (not sequenced fields) and call Save()
- Create a new entity, set the primary key values, set the IsNew to false, set one or more other fields' values and call Save(). This will not alter the PK fields.
- Via one of the UpdateMulti() methods defined in the collection class of the entity.
Altering entity property values
The Save() method will see that the entity isn't new, and will use an UPDATE query to alter the entity's data in the persistent storage and an INSERT query to insert a new instance into the persistent storage. An UPDATE query will only update the changed fields in an entity that is saved.
If no fields are changed, no update is performed. If you've loaded an entity from the database into memory and you've changed one or more of its primary key fields, these fields will be updated in the database as well (except sequenced columns). Changing PK fields is not recommended and changed PK fields are not propagated to related entities fetched in memory.
An example for code using the first method:
var customer = new CustomerEntity("CHOPS"); // fetches the entity
customer.Phone = "(605)555-4321";
customer.Save();
This will first load the Customer entity "CHOPS" into memory, alter one field, Phone, and then save the entity instance back into the persistent storage. Because the loading of "CHOPS" already set the primary key, we can just alter a field and call Save() . The Update query will solely set the table field related to the entity field "Phone" to the new value.
Update an entity directly in the database
Reading an entity into memory first can be somewhat inefficient, if all we need to do is an update of an entity row in the database. The following procedure is more efficient in that it results in just an UPDATE query, without first reading the entity data from the database. The following code performs the same update as the previous example code illustrating option 1.
Because it doesn't need to read an entity first, we won't pass true to keep the connection open. Even though the PK field is changed, it is not updated, because it is not previously fetched from the database.
var customer = new CustomerEntity(); // no fetch as no PK is specified
customer.CustomerID="CHOPS";
customer.Phone = "(605)555-4321";
customer.IsNew=false;
customer.Save();
We have to set the primary key field, so the Update method will only update a single entity, the "CHOPS" entity. First we specify the altering of a field, in this case Phone. Next, we have to mark the new, empty entity class instance as not being new, so Save() will use an UPDATE query, instead of an INSERT query.
This is done by setting the flag IsNew to false. We'll set IsNew to false right before saving the entity. The reason to do this as the last action is to make it possible to set a field to null / Nothing using this system: setting a field to null / Nothing is a 'change of value' for new entities but for existing entities, if a field is already null / Nothing (which is the case with a new entity object) it isn't (null / Nothing changed into null / Nothing), and the field isn't seen as 'changed' and isn't updated. As the last action we call Save().
This will not load the entity back in memory, however because Save() is called, it will be marked out of sync, and the next time you'll access a property of this entity's object, it will be refetched from the persistent storage. Doing updates this way can be very efficient and you can use very complex update constructs when you apply an Expression to the field(s) to update. See for more information about Expression objects for fields Field expressions and aggregates.
- This same mechanism will work for fast deletes.
- Setting a field to the same value it already has will not set the field to a value (and will not mark the field as 'changed') unless the entity is new.
- Each entity which is saved is validated prior to the save action. This validation can be a no-op, if no validation code has been added by the developer, either through code added to the entity, or through a validator class. See Validation per field or per entity for more information about LLBLGen Pro's validation functionality.
-
(SQLServer specific) If the entity is saved into a table which is
part of an indexed view, SqlServer requires that
SET ARITHABORT ON
is specified prior to the actual save action. You can tell LLBLGen Pro to set that option, by calling the global method CommonDaoBase.SetArithAbortFlag(bool) method. After each SQL statement aSET ARITHABORT OFF
statement will be executed if the ArithAbort flag is set to true. Setting this flag affects the whole application.
Using UpdateMulti()
Entity collection classes allow you to manipulate an entity or group of entities directly in the database without first fetching them into memory. Below we're setting all 'Discontinued' fields of all product entities to false if the CategoryId of the product is equal to 3. UpdateMulti() (as well as its method for deletes DeleteMulti which deletes entities directly from the persistent storage) returns the number of entities affected by the call.
var filter = ProductFields.CategoryId.Equal(3);
var updateValuesProduct = new ProductEntity();
updateValuesProduct.Discontinued=true;
var products = new ProductCollection();
products.UpdateMulti(updateValuesProduct, filter);
Saving entities recursively
All entity objects and entity collection objects in SelfServicing support recursive saves. This means that if you have an entity object, say a CustomerEntity, and its collection objects, e.g. customer.Orders, contain changed entities, or the entity references changed entities, these entities will be saved as well when the particular entity is saved.
In SelfServicing, this logic is not enabled by default, to be backwards compatible. You have to call the Save() (entities) or entitycollection.SaveMulti() (entity collections) overloads which accept a boolean parameter to signal the routine to save all entities recursively or not.
Pass true to the Save / SaveMulti call and the whole object graph is saved, that is: all entities reachable from the object the Save (or SaveMulti) method is called on which are changed ('dirty').
All recursive save actions are performed inside a transaction. If the saved entity (the entity the Save() method is called on) or the saved entity collection is not participating in a transaction, a new transaction is created (ADO.NET transaction).
If there is already a transaction available, it is assumed all entities to save participate already in this transaction or can participate in this transaction (i.e. are not participating in another transaction). If an error occurs during the recursive save, the current transaction is aborted and the transaction is rolled back.
The logic automatically determines the order in which actions need to take place so foreign key violations do not occur.
For example:
- Instantiate a Customer entity, add a new Order object to its Orders collection. Now add OrderDetails objects to the new Order object's OrderDetails collection,. You can simply save the Customer entity and all included new/'dirty' entities will be saved and any PK-FK relations will be updated/synchronized automatically.
- Alter the Customer object in the example above, and save the Order object. The Customer object is saved first, then the Order and then the OrderDetails objects with all PK-FK values being synchronized