Alok Patel
Alok Patel

Reputation: 8012

Resuing IDBTransaction in callbacks throws TransactionInactiveError

I'm developing a app which uses IndexedDB extensively. What I'm trying to do is save data of employees table and company table.

Each employee belongs to a company and in employee object I've Company's ID and the objects of both of the entity will look like this.

Company's object:

{"id":1,"name":"ABC"}

Employee's object:

{"id":100,"name":"E1","company_id":1}

I'm saving company's details using auto-incremented key (called it appid), so my final object of company's look like this:

{"id":1,"name":"ABC","appid":1}

Where the appid will get auto-incremented as I insert records of company one by one.
Now while inserting employee's object I want to find the localid(appid) of the company and save it in employee's object to make employee's object look like:

{"id":100,"name":"E1","company_id":1,"company_app_id":1}

I'm able to get the localid of the company by calling a method while saving employee's details, like:

var transaction = db.transaction(['employees'], 'readwrite');
var objStore = transaction.objectStore('employees');
var company_id=employeeobject.company_id;
companyDB.getCompanyById(company_id,function(companyObject){
      transaction = db.transaction(['employees'], 'readwrite');
      objStore = transaction.objectStore('employees');
      // If I comment above two lines it throws me exception.
      var request=objStore.put(employeeobject);
      request.onsuccess = function (e) {
          // using it for next insertion.
      };
});

Problem with the above code is every time when I want to insert employee's data in table I need to reopen the trascation in callback function because if I don't open the transaction again it throws TransactionInactiveError.

I've searched for specific error on SO and found that Transaction get inactive as soon as it's no more used in current scope.

Above code work perfectly fine when I've couple of employee's objects. But When I'm trying to execute the same code with ~1K of data it takes (normal execution time x ~10).

By normal execution time I mean without fetching company's localid and saving employee's details directly.


So my question is, what is the best way I can insert the employee's data including company's localid with least execution time? Or Am I doing something wrong ?

Upvotes: 0

Views: 126

Answers (2)

Joshua Bell
Joshua Bell

Reputation: 8337

It depends on how you're implementing companyDB.getCompanyById().

As presented, it's an asynchronous black box (maybe it's doing a network request?) And as you've discovered, Indexed DB transactions are only active (1) directly after creation and (2) in callbacks from requests made in that transaction, until "control returns to the event loop". Without further details, your best bet would be to batch the work - do the getCompanyById() lookups for N employees, then write those N records.

But from the description at the top "...data of employees table and company table..." maybe this is all within a single Indexed DB database, in which case just use a single transaction for everything:

 var tx = db.transaction(['companies', 'employees'], 'readwrite');
 employee_records.forEach(function(record) {
   var company_id = record.company_id;
   var req = tx.objectStore('companies').get(company_id);
   req.onsuccess = function() {
     var company = req.result;
     record.company_app_id = company.app_id;
     tx.objectStore('employees').put(record);
   };
 });

(I'm mangling your actual data/logic here, this is just to illustrate)

Upvotes: 1

Josh
Josh

Reputation: 18690

Hmm, maybe something like this helps?

function addCompany(db, company, callback) {
  var tx = db.transaction('companies', 'readwrite');
  var store = tx.objectStore('companies');
  var request = store.add(company);
  request.onsuccess = callback;
}

function addEmployee(db, employee, callback) {
  var tx = db.transaction('employees', 'readwrite');
  var store = tx.objectStore('employees');
  var request = store.add(employee);
  request.onsuccess = callback;
}


function addCompanyThenEmployee(db, company, employee, callback) {
  addCompany(db, company, onAddCompany);

  function onAddCompany(event) {
    var newAppId = event.target.result;
    employee.company_app_id = newAppId;
    addEmployee(db, employee, callback);
  }
}


var company = {'id': 1, 'name': 'xyz'};
var employee = {'id': 1, 'name': 'xyz'};

var request = indexedDB.open(...);
request.onsuccess = function(event) {
  var db = event.target.result;
  addCompanyThenEmployee(db, company, employee, onAddCompanyThenEmployee.bind(null, company, employee));
};

function onAddCompanyThenEmployee(company, employee, event) {
  console.log('Added company', company, 'and employee', employee);
};

Upvotes: 0

Related Questions