Reputation: 1810
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?
Upvotes: 1
Views: 1484
Reputation: 1857
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
}));
}
Upvotes: 0
Reputation: 1810
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.
Upvotes: 0