Back to Devexpress

ExplicitUnitOfWork Class

xpo-devexpress-dot-xpo-a250d372.md

latest11.3 KB
Original Source

ExplicitUnitOfWork Class

The ‘unit of work’ that uses long database level transaction to allow you to simplify the management of object changes and to access modified objects without having to commit the changes beforehand.

Namespace : DevExpress.Xpo

Assembly : DevExpress.Xpo.v25.2.dll

NuGet Package : DevExpress.Xpo

Declaration

csharp
public class ExplicitUnitOfWork :
    UnitOfWork
vb
Public Class ExplicitUnitOfWork
    Inherits UnitOfWork

Remarks

An explicit unit of work is a UnitOfWork descendant that uses long database level transaction to isolate object changes at the database level. Because of this, persistent objects are temporarily stored in a database, allowing you to access these objects as if they were already stored in the database.

Important

An Explicit Unit of Work that starts an database level transaction must be the exclusive owner of the database connection. Therefore, only one database level transaction can be open at a time. That’s why you cannot use an Explicit Unit of Work within another Explicit Unit of Work. However, you can create Nested Units of Work within an Explicit Unit of Work , if necessary.

Managing Database Level Transaction

Within an explicit unit of work , you can execute transaction commands (start a database level transaction, commit all temporary changes or roll them back) at any time, just like regular transactions, using methods displayed in the following table.

|

Transaction Command

|

Method

| | --- | --- | |

BEGIN

|

ExplicitUnitOfWork.BeginTransaction

| |

COMMIT

|

ExplicitUnitOfWork.CommitTransaction

UnitOfWork.CommitChanges

UnitOfWork.CommitChangesAsync

ExplicitUnitOfWork.CommitTransactionAsync

| |

ROLLBACK

|

ExplicitUnitOfWork.RollbackTransaction

|

As with regular transactions, the BEGIN command marks the point at which the data referenced by an explicit unit of work is consistent. All data modifications made after this command can be rolled back. This allows data to be returned to this known state of consistency. Each transaction lasts until either the COMMIT or ROLLBACK command is executed. The COMMIT command writes the modifications. The ROLLBACK command discards all the changes made.

To make things simple, an explicit unit of work automatically starts a database level transaction before data modifications are temporarily saved to a database for the first time. So, there is no need to start a database level transaction manually within an explicit unit of work.

csharp
using (ExplicitUnitOfWork euow = new ExplicitUnitOfWork(session1.DataLayer)) {
    // Starts tracking changes to persistent objects.
    Person person = new Person(euow);
    person.Name = "Thomas Brown";
    person.Age = 33;

    // Starts a database level transaction and flushes all intermediate object changes to a database.
    // Thus, person has been temporarily stored to a database and FindObject locates this person.
    Person savedPerson = euow.FindObject<Person>(CriteriaOperator.Parse(
        "Name = ? And Age = ?", person.Name, person.Age));

    savedPerson.Name = "James Smith";
    savedPerson.Age = 60;

    // Updates person with new data and commits the database level transaction.
    euow.CommitChanges();
}
vb
Using euow As New ExplicitUnitOfWork(session1.DataLayer)
    ' Starts tracking changes to persistent objects.
    Dim person As New Person(euow)
    person.Name = "Thomas Brown"
    person.Age = 33

    ' Starts a database level transaction and flushes all intermediate object changes to a database.
    ' Thus, person has been temporarily stored to a database and FindObject locates this person.
    Dim savedPerson As Person = euow.FindObject(Of Person)(CriteriaOperator.Parse( _
    "Name = ? And Age = ?", person.Name, person.Age))

    savedPerson.Name = "James Smith"
    savedPerson.Age = 60

    ' Updates person with new data and commits the database level transaction.
    euow.CommitChanges()
End Using

Managing Object Changes

Like regular units of work, explicit units of work automatically track all changes made to persistent objects. Due to the database level transactions, you can access modified objects without having to commit the changes beforehand. As shown in the example above, the newly created Person object is retrieved by the Session.FindObject<ClassType> function, as if it was already stored in a database.

In addition, you can manually manage changes within an explicit unit of work via the Session.DropChanges, Session.FlushChanges, and Session.FlushChangesAsync methods, as shown in the example below.

csharp
using (ExplicitUnitOfWork euow = new ExplicitUnitOfWork(session1.DataLayer))
{
    Person person1 = new Person(euow); // Starts tracking changes to persistent objects
    person1.Name = "Thomas Brown";
    person1.Age = 33;
    // Starts a database level transaction and saves person1 to a database.
    euow.FlushChanges();

    // Create person2 with the same name.
    Person person2 = new Person(euow);
    person2.Name = person1.Name;
    person2.Age = 60;
    // Discards person2.
    euow.DropChanges();

    // The collection retrieves only person1.
    XPCollection<Person> savedPerson = new XPCollection<Person>(euow, 
        CriteriaOperator.Parse("Name = ?", person1.Name));
    // ...
}
vb
Using euow As New ExplicitUnitOfWork(session1.DataLayer)
    Dim person1 As New Person(euow) ' Starts tracking changes to persistent objects
    person1.Name = "Thomas Brown"
    person1.Age = 33
    ' Starts a database level transaction and saves person1 to a database.
    euow.FlushChanges()

    ' Create person2 with the same name.
    Dim person2 As New Person(euow)
    person2.Name = person1.Name
    person2.Age = 60
    ' Discards person2.
    euow.DropChanges()

    ' The collection retrieves only person1.
    Dim savedPerson As New XPCollection(Of Person)(euow, _
    CriteriaOperator.Parse("Name = ?", person1.Name))
    ' ...
End Using

Note

Methods performing transaction operations (see the table in the previous section) automatically call Session.DropChanges (ROLLBACK) or Session.FlushChanges (BEGIN OR COMMIT) for your convenience.

Managing object changes using explicit units of work is handy when intermediate object updates may violate database constraints. To avoid constraint violations, all intermediate object changes are applied temporarily within an explicit unit of work, using Session.FlushChanges.

Consider an example when a field has a unique constraint in the database, and you need to make changes that can violate these constraints. In other words, you need to remove the object and create a new one, but with the same identifier. The code below shows how this can be accomplished. Note that the Oid key field is not auto-incremented.

csharp
public class Person: XPLiteObject {
     int oid;

     [Key]
     public int Oid {
         get { return oid; }
         set { SetPropertyValue<int>(nameof(Oid), ref oid, value); }
     }

     // ...
     public Person(Session session): base(session) {
     }
 }

// ...

using(ExplicitUnitOfWork euow = new ExplicitUnitOfWork(session1.DataLayer)) {
    // Load person with a key '5'.
    Person person = euow.GetObjectByKey<Person>(5);

    // Delete it.
    euow.Delete(person);

    // Start a database level transaction and flush all intermediate object changes to a database.
    euow.FlushChanges();

    // Create a new object with a key '5'.
    Person personNew = new Person(euow);
    personNew.Oid = 5;
    personNew.Name = "Thomas Brown";
    personNew.Age = 34;

    // Save everything and commit the database level transaction.
    euow.CommitChanges();
}
vb
Public Class Person
    Inherits XPLiteObject
     Private oid_ As Integer

     <Key> _
     Public Property Oid() As Integer
         Get
             Return oid_
         End Get
         Set(ByVal value As Integer)
             SetPropertyValue(Of Integer)(NameOf(Oid), oid_, value)
         End Set
     End Property

     ' ...
     Public Sub New(ByVal session As Session)
         MyBase.New(session)
     End Sub
End Class

' ...

Using euow As New ExplicitUnitOfWork(session1.DataLayer)
    ' Load person with a key '5'.
    Dim person As Person = euow.GetObjectByKey(Of Person)(5)

    ' Delete it.
    euow.Delete(person)

    ' Start a database level transaction and flush all intermediate object changes to a database.
    euow.FlushChanges()

    ' Create a new object with a key '5'.
    Dim personNew As New Person(euow)
    personNew.Oid = 5
    personNew.Name = "Thomas Brown"
    personNew.Age = 34

    ' Save everything and commit the database level transaction.
    euow.CommitChanges()
End Using

Note that when using explicit units of work, your persistent classes should not make database queries from IXPObject.OnSaving method overloads. Thus, you cannot modify an object state via the OnSaving method.

Implements

ISessionProvider

Inheritance

Object MarshalByRefObject Component Session UnitOfWork ExplicitUnitOfWork

Extension Methods

Query<T>()

QueryInTransaction<T>()

See Also

ExplicitUnitOfWork Members

UnitOfWork

Database Level Transactions

NestedUnitOfWork

BeginTrackingChanges()

DevExpress.Xpo Namespace