1

As there are many IDs in the system, my entities linked to database tables and the tables use 'DbId' as the primary key - instead of the ngrx/data default: 'id'.

That is addressed inside the EntityMetadata map by the property: selectId. I followed the documentation here and practically my setup is done that way. All appears working fine, except when adding records to db table.

The addition to the db table proceeds, but after, on the client site, ngrx/data generates error: has a missing or invalid entity key (id) by the: EntityActionGuard.

Here are the relevant code snippets:

                    /**
                     * Authority roles assigned to user
                     * 
                     */
export class UserRolesEntity {
  DbId?: number;
  DbId_User?: number;
  DbId_Role?: number;
  Timestamp?: Date;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - -

export const entityMetadata: EntityMetadataMap = {
. . .
User_Roles: { selectId: (user_roles: UserRolesEntity) => user_roles.DbId },
. . . 
}

.

class NgrxDataService_UR<User_Roles> extends EntityCollectionServiceBase<User_Roles>

. IN COMPONENT:

constructor(dsUR: NgrxDataService_UR) { . . . }
. . .
fn() {
  const addItem: UserRolesEntity = {
    DbId_User: 3,
    DbId_Role: 11
  }
  this.dsUR.add(addItem);
}

The step creates entry in the database table. Back on client, in debugger, I see NgRx/data utilizes class: EntityActionGuard and fn: mustBeEntity(action) { . . .}

My returned action looks like this:

>payload:
correlationId: "CRID14"
data: Array(1)
>0: {DbId: 29,               <<<----
     DbId_Role: 11,
     DbId_User: 3}
[[Prototype]]: Object
length: 1
[[Prototype]]: Array(0)
entityName: "User_Roles"
entityOp: "@ngrx/data/save/add-one/success"
isOptimistic: false
[[Prototype]]: Object
type: "[User_Roles] @ngrx/data/save/add-one/success"

Note the property DbId in data - it is there with a value ! Still the fn: inside mustBeEntity(action) returns undefined !

const id = this.selectId(data);
// id is undefined 

What may be wrong here ?

Edit:

I have upgraded from Angular 8 to Angular 13. Could this be an issue?

Felix
  • 1,662
  • 2
  • 18
  • 37
  • could you share a little of your reducer? specifically the part where you define the `EntityAdapter` ? – The Fabio Jan 12 '22 at 21:26
  • In ngrx/data I do not need to define reducers. Except what I have posted, the rest is practically the same as per the documentation: https://github.com/johnpapa/ngrx-data-lab/blob/master/README.md – Felix Jan 13 '22 at 00:03

2 Answers2

0

For you colleagues who encounter similar issue.

Make sure the server end returns the proper data type, the same type, the client end expects. In my case the problem was that the server end was string-ifying the response, while it should have been returning the response object as such.

Hope that helps someone dealing with similar pitfall.

Felix
  • 1,662
  • 2
  • 18
  • 37
0

Finally, I got the solution:

We need to write a custom data service that extends default data service of ngrx/data.

@Injectable()
export class ForReportsDataService extends DefaultDataService<any>{}

and define the CRUD operation and make sure you return the specific object.

Here in my case, I need whatever is there inside the item object.

    // POST /api/for-reports
    add(entity: ForReport): Observable<any> {
        return from(this.dataService.POST("/api/reports", entity).then(res => {
            return res["item"]; // CHECK THIS IS CORRECT IN YOUR CASE
        }));
    }
Parth Developer
  • 1,371
  • 1
  • 13
  • 30