Unit of Work - Hookyns/unimapperjs GitHub Wiki
Unit of Work
Unit of Work is quite important part. If you work with some data, you want to keep it consistent. Because of that there are Transactions. In ORM/ODM world it's not enought. For example, you have instance of Employee. You create transaction, change employee's name and something happen, some error has been throwed. You'll rollback changes in DB but this change is still in instance on given employee and you can't do anything.
Examples
Example 1
// imports...
// let teacher = ....
// You want to create students, let's say one depends on the other for any reason..
let s1 = new Student({
name: "Student no. 1",
teacherId: teacher.id
});
let s2 = new Student({
name: "Student no. 2",
teacherId: teacher.id
});
await $um.UnitOfWork.create(async (uow) => {
uow.insert(s1); // insert first student
// This logic can be in different method eg.
await uow.nest(async (uow) => {
uow.insert(s2); // insert second student
s1.name = "Different Name"; // Some action over student s1
await uow.saveChanges();
});
// Do something else... but,.. what?
throw new Error("Something hapenned here");
await uow.saveChanges();
});
As result of this example, no student has been inserted into storage. Major UoW didn't saveChanges() so all've been rolled back.
Example 2
// imports...
// let teacher = ....
// You want to create students, let's say one depends on the other for any reason..
let s1 = new Student({
name: "Student no. 1",
teacherId: teacher.id
});
let s2 = new Student({
name: "Student no. 2",
teacherId: teacher.id
});
await $um.UnitOfWork.create(async (uow) => {
uow.insert(s1); // insert first student
// This logic can be in different method eg.
await uow.nest(async (uow) => {
uow.snap(s1); // Create s1's state snapshot which will be recovered while rollback of this uow
uow.insert(s2); // insert second student
s1.name = "Different Name"; // Some action over student s1
// Do something else... but,.. what?
throw new Error("Something hapenned here");
await uow.saveChanges();
});
await uow.saveChanges();
});
As result of this example, student s1 has been inserted into storage and his name is 'Student no. 1', same as name in instance s1 because it was rolled back too, not just in storage. In nested uow there were and error so nothing inside that uow take effect.
Example 3
// imports...
await $um.UnitOfWork.create(async (uow) => {
// Create Teacher
let teacher = new Teacher({
firstName: "John",
lastName: "Wick"
});
// Not related nested UoW
await $um.UnitOfWork.create(async (uow) => { // It's normal major uow, not uow.nest()
uow.insert(teacher);
// throw new Error("Some error...");
await uow.saveChanges();
}); // Autoincrement Id of teacher was set after nested uow commit
// Insert students
let s1 = new Student({
name: "Student no. 1",
teacherId: teacher.id
});
uow.insert(s1);
let s2 = new Student({
name: "Student no. 1",
teacherId: teacher.id
});
uow.insert(s2);
await uow.saveChanges();
});
As result of this example, teacher and his two students has been stored. Nested UoW is standalone UoW because teacher's id is needed but it'll be not set until it commit. But still, if some error occurs, major UoW is not going to be commited.