Subsonic 3 .Save() VS .Update() and .Add() - subsonic

What is the difference between:
.Save();
.Add();
.Update():

You don't mention which templates you're using (I'm going to assume ActiveRecord), but as a general rule:
Save will insert if the object
IsNew==true or otherwise it will
update.
Add will always insert a new record.
Update will only update an object
with IsNew==false and will fail if
there is no corresponding record in
the db for the instance.

Related

Validate #versionColumn value before saving an entity with TypeORM

I'm currently working on saving data in a postgres DB using TypeORM with the NestJS integration. I'm saving data which keeps track of a version property using TypeORM's #VersionColumn feature, which increments a number each time save() is called on a repository.
For my feature it is important to check this version number before updating the records.
Important
I know I could technically achieve this by retrieving the record before updating it and checking the versions, but this leaves a small window for errors. If a 2nd user updates the same record in that millisecond between the get and save or if it would take longer for some weird reason, it would up the version and make the data in the first call invalid. TypeORM doesn't check the version value, so even if a call has a lower value than what is in the database, it still saves the data eventhough it should be seen as out of date.
1: User A checks latest version => TypeORM gives back the latest version: 1
2: User B updates record => TypeORM ups the version: 2
3: User A saves their data with version 1 <-- This needs to validate the versions first.
4: TypeORM overwrites User B's record with User A's data
What I'm looking for is a way to make TypeORM decline step 3 as the latest version in the database is 2 and User A tries to save with version 1.
I've tried using the querybuilder and update statements to make this work, but the build-in #VersionColumn only up the version on every save() call from a repository or entity manager.
Besides this I also got a tip to look into database triggers, but as far as I could find, this feature is not yet supported by TypeORM
Here is an example of the setup:
async update(entity: Foo): Promise<boolean> {
const value = await this._configurationRepository.save(entity);
if (value === entity) {
return true;
}
return false;
}
In my opinion, something like this is much better served through triggers directly in the Database as it will fix concerns around race conditions as well as making it so that modifications made outside the ORM will also update the version number. Here is a SQL Fiddle demonstrating triggers in action. You'll just need to incorporate it into your schema migrations.
Here is the relevant DDL from the SQL Fiddle example:
CREATE TABLE entity_1
(
id serial PRIMARY KEY,
some_value text,
version int NOT NULL DEFAULT 1
);
CREATE OR REPLACE FUNCTION increment_version() RETURNS TRIGGER AS
$BODY$
BEGIN
NEW.version = NEW.version + 1;
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
CREATE TRIGGER increment_entity_1_version
BEFORE UPDATE
ON entity_1
FOR EACH ROW
EXECUTE PROCEDURE increment_version();
The same trigger function can be used for any table that has a version column in case this is a pattern you want to use across multiple tables.
I think you are looking for concurrency control. If this is the case there is a solution in this about 1/2 the way down. TypeORM concurrency control issue

How to get an instance of the updated sequelize model from an afterUpsert hook?

Other sequelize hooks, like afterUpdate(instance, options) provide an instance of the modified model as a parameter. However, afterUpsert(created, options) provides a created boolean which indicates if the operation was a insert or update.
Is there a way to configure sequelize, or manipulate the afterUpsert parameters, to obtain an instance of the upserted model?
As far as I know you can not. As the result of upsert call to db via queryInterface is what is returned to the afterUpsert hook, which is boolean value whether there has been any newly created records or not in the upsert process.
While, you can use beforeUpsert with the values passed to upsert method. Not sure if that might be helpful ( may be to clear a cache )
I have faced the same issue recently, and I was able to manage it this way:
beforeUpsert: (values, options)=>{
/* afterUpsert will always get an array of type [Model, created] as first argument */
options.returning = true;
},
I decided to use the beforeUpsert hook to make sure that any call to Model.upsert is forced to return an instance and not only a created boolean. But, you can also call
upsert(values,{returning: true});
HTH

How can I get the entire updated entry in a $afterUpdate hook in objection models?

Im using Objection.js as my ORM for a simple rainfall application. I need to be able to dynamically update and entry of one table when a lower level tables entires has been updated. To do this I need the whole entry I am updating so I can use that data to correctly update the dynamically updated entry.
Im using the $afterUpdate hook for the lower level table entry which. The issue I am having is that when I log this within the $afterUpdate hook function it only contains the properties for the parts of the entry I want to update. How can I get the entire entry? Im sure I could get the record by running an additional query to the DB but I was hoping there would be away to avoid this. Any help would be appreciated
I think, as of right now, you can only get the whole model with an extra query.
If you are doing the update with an instance query ($query) you can get the other properties from options.old.
Query:
const user = await User.query().findById(userId);
await user.$query()
.patch({ name: 'Tom Jane' })
Hook:
$afterUpdate(opt, queryContext) {
console.log(opt.old)
}
Patch
If you don't need to do this in the hook, you might want to use patch function chained with first().returning('*') to get the whole model in a single query, it's more efficient than patchAndFetchById in postgreSQL. Like stated in the documentation.
Because PostgreSQL (and some others) support returning('*') chaining, you can actually insert a row, or update / patch / delete (an) existing row(s), and receive the affected row(s) as Model instances in a single query, thus improving efficiency. See the examples for more clarity.
const jennifer = await Person
.query()
.patch({firstName: 'Jenn', lastName: 'Lawrence'})
.where('id', 1234)
.returning('*')
.first();
References:
http://vincit.github.io/objection.js/#postgresql-quot-returning-quot-tricks
https://github.com/Vincit/objection.js/issues/185
https://github.com/Vincit/objection.js/issues/695

How do I do atomic update using Bookshelf.js model?

For example, if I wanted to do something like the following in MySQL query:
update foo set bar = bar + ?;
How would I achieve this using Bookshelf.js model?
I'm not exactly sure what you mean by atomic, perhaps transactions? You can do that in bookshelf, there's a whole section about it: http://bookshelfjs.org/#Bookshelf-transaction
However, if you're just trying to update a field, you can do that easily as follows:
var idStationIWantToUpdate = 1;
new Station({'id': idStationIWantToUpdate}).save({
route_name: 'my updated route name'
}).then(function(station) {
res.json(station.toJSON());
});
The important part is that you instantiate a model with the corresponding ID, then when you call save, it automatically updates the existing record.
I couldn't get this to work as I expect it, but there's an increment method in the knex query builder library (http://knexjs.org/#Builder-increment) which is the underlying engine for this functionality in bookshelf.js
What I ended up doing was:
foo.forge().save({bar:bookshelf.knex.raw('bar + 1')},{method:"update"});

I do not want my updates to do an add if entity does not exist

I want to be able to provide an UPDATE method to my users that will update the record they specify based on RowKey but it will NOT ADD it if the RowKey they pass in does not exist.
My reasoning is that if they mistakenly send in an invalid RowKey, I do not want them unknowingly ending up with a new entity vs. having updated the one they intended to update in the first place.
Here is the gist of the code I have (but that Adds/inserts the entity if it does not exist):
' p below is the entity obj (Inherits from TableServiceEntity)
' PartitionKey and RowKey are set to values of entity to update
MyBase.AttachTo(_tableName, p)
MyBase.UpdateObject(p)
MyBase.SaveChangesWithRetries(Services.Client.SaveChangesWithOptions.Batch)
My issue is that I was expecting to get some exception thrown when SaveChanges executed and no entity with matching PK and RK was found. Instead the entity with the new PK, RK combination is added.
How can I structure my code so that only an UPDATE is done and no ADD if PK, RK is not existent?
I believe if you call the three argument version of AttachTo(), you will get the desired behavior.
MyBase.AttachTo(_tableName, p, "*");
But I haven't actually tried it.
Rather than catching an error when you try to update and item that doesn't exists (I believe breischl is right about how to avoid that) the easiest thing to do would be to run a query to check if it does actually exist first.

Resources