cancel
Showing results for 
Search instead for 
Did you mean: 

SAP CAP ReferentialConstraint metadata wrongly generated for composition projection

felipediasmarisa
Explorer
0 Kudos

The ReferentialConstraint element generated on the OData metadata seems to have the Property and ReferencedProperty inverted for one of the projections (TaskSync):

The generated OData metadata has the following navigation to pricechangeDetail for the Task and TaskSync entities respectively:

<EntityType Name="Task">
...
<NavigationProperty Name="pricechangeDetail" Type="CatService.PricechangeDetail" Partner="task">
<OnDelete Action="Cascade"/>
<ReferentialConstraint Property="ID" ReferencedProperty="task_ID"/>
</NavigationProperty>
</EntityType>

<EntityType Name="TaskSync">
...
<NavigationProperty Name="pricechangeDetail" Type="CatService.TaskSyncPricechangeDetail">
<OnDelete Action="Cascade"/>
<ReferentialConstraint Property="task_ID" ReferencedProperty="ID"/>
</NavigationProperty>
</EntityType>

DB entity definitions:

entity Task : cuid {
title : String(100);
//...
pricechangeDetail : Composition of one PricechangeDetail
on pricechangeDetail.task = $self;
}; entity PricechangeDetail {
key task : Association to Task;
products : Composition of many PricechangeProduct
on products.parent = $self; //...
};

entity PricechangeProduct {
key parent : Association to one PricechangeDetail;
key sku : Product:sku;
description : Product:description;
//...
};

Service definitions:

@cds.redirection.target
entity Task as projection on db.Task;

@cds.redirection.target
@readonly
entity PricechangeDetail as projection on db.PricechangeDetail;

@cds.redirection.target
@readonly
entity PricechangeProduct as projection on db.PricechangeProduct;


@readonly
entity TaskSyncPricechangeProduct as projection on db.PricechangeProduct {
key parent,
key sku,
//...
}

@readonly
entity TaskSyncPricechangeDetail as projection on db.PricechangeDetail {
key task,
products : redirected to TaskSyncPricechangeProduct
}

@restrict: [{grant: [
'UPDATE',
'READ'
]}]
entity TaskSync as projection on db.Task {
key ID,
//...
pricechangeDetail : redirected to TaskSyncPricechangeDetail
}

I don't understand why the Property and ReferencedProperty attributes are swapped in the TaskSync projection navigation, this is causing an issue in a consuming application and the only solution I found so far is to manually change the generated OData metadata before importing in the consuming application.

How can I fix this problem in the definitions?

Or is there at least a way I can programatically overwrite the generated OData metadata?

Thank you all in advance

Accepted Solutions (1)

Accepted Solutions (1)

cwedler
Employee
Employee

The issue here is that you have two projections per db entity in your service, but there are `redirected to`s missing to connect them.

Remark: if you are free to change your names, you could make use of the name-prefix aware auto-redirection feature of the compiler. See a slight variant of your model where 4 projections and all `redirected to`s are done automatically:

context db {
  entity Task {
    key id: UUID;
    title: String;
    pricechangeDetail  : Composition of one Task.PricechangeDetail
    on pricechangeDetail.task = $self;

  }

  entity Task.PricechangeDetail {
    key task     : Association to Task;
    products : Composition of many Task.PricechangeProduct
    on products.parent = $self;
  };

  entity Task.PricechangeProduct {
    key parent          : Association to one Task.PricechangeDetail;
    key sku             : Integer;
    description         : String;
  }
}

service S {
  entity Task as projection on db.Task;
  entity TaskSync as projection on db.Task;
}
felipediasmarisa
Explorer
0 Kudos

Hi Christoph, thank you for your answer!

But I've failed to understand the issue and the fix.

The reason why I have explicitly exposed the entities and manually redirected to TaskSyncPricechangeProduct and TaskSyncPricechangedDetail from the TaskSync is that the TaskSync variant of those entities only expose a subset of the fields. So I have a default Task projection which is the full entity in readonly mode, and a TaskSync variant where there is a subset of the fields but write is supported.

Is there a way to fix this but still keep 2 different projections?

cwedler
Employee
Employee

Having these two variants is absolute fine, although a bit tedious to write if both are in the same service and not using the above-mentioned naming scheme.

Ok, here now for your entity names. By “connecting via 'redirected to'”, I mean having 8 `redirected to`s ,not just one:

context db {
  entity Task {
    key id: UUID;
    title: String;
    pricechangeDetail  : Composition of one PricechangeDetail
                           on pricechangeDetail.task = $self;

  }

  entity PricechangeDetail {
    key task     : Association to Task;
    products : Composition of many PricechangeProduct
                 on products.parent = $self;
  };

  entity PricechangeProduct {
    key parent          : Association to one PricechangeDetail;
    key sku             : Integer;
    description         : String;
  }
}

service S {
  entity Task as projection on db.Task { *,
    pricechangeDetail: redirected to PricechangeDetail };
  entity PricechangeDetail as projection on db.PricechangeDetail { *,
    task: redirected to Task,
    products: redirected to PricechangeProduct
  }
  entity PricechangeProduct as projection on db.PricechangeProduct { *,
    parent: redirected to PricechangeDetail
  }

  entity TaskSync as projection on db.Task { *,
    pricechangeDetail: redirected to TaskSyncPricechangeDetail };
  entity TaskSyncPricechangeDetail as projection on db.PricechangeDetail { *,
    task: redirected to TaskSync,
    products: redirected to TaskSyncPricechangeProduct
  }
  entity TaskSyncPricechangeProduct as projection on db.PricechangeProduct { *,
    parent: redirected to TaskSyncPricechangeDetail
  }
}

(This code is without annotations and excluded elements, I just show the `redirected to`. BTW, leave out the `@cds.redirection.target` annotations, they are just confusing when they have no effect)

Then all ReferentialConstraint in the OData should be fine

felipediasmarisa
Explorer
0 Kudos

Thank you very much, this solved my problem!

Answers (0)