Skip to content

Commit 52f41dc

Browse files
akoclaude
andcommitted
fix: default CreatableFromParent/UpdatableFromParent from FROM entity set
Navigation associations whose FROM entity is top-level (has its own entity set) now inherit CreatableFromParent / UpdatableFromParent from the entity set's Insertable / Updatable annotations — silent metadata defaults to false, matching Studio Pro. Previously the defaults were optimistically true, which produced CE6630 errors for read-only services like TripPin whose metadata declares no InsertRestrictions. Verified against TripPin's Friends / BestFriend self-references on People (silent metadata): CreatableFromParent=False, as Studio Pro writes them. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 6be89fe commit 52f41dc

1 file changed

Lines changed: 19 additions & 7 deletions

File tree

mdl/executor/cmd_contract.go

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -884,12 +884,15 @@ func (e *Executor) createNavigationAssociations(
884884
esMap map[string]string,
885885
serviceRef string,
886886
) int {
887-
// Build per-entity-type lookup of nav property name → restricted flags.
887+
// Build per-entity-type lookup of nav property name → restricted flags,
888+
// plus a direct entity-set lookup so we can read the base Insertable /
889+
// Updatable defaults for the FROM entity.
888890
type navRestrictions struct {
889891
nonInsertable map[string]bool
890892
nonUpdatable map[string]bool
891893
}
892894
restrictionsByType := make(map[string]navRestrictions)
895+
esByType := make(map[string]*mpr.EdmEntitySet)
893896
for _, es := range doc.EntitySets {
894897
r := navRestrictions{
895898
nonInsertable: make(map[string]bool),
@@ -902,6 +905,7 @@ func (e *Executor) createNavigationAssociations(
902905
r.nonUpdatable[name] = true
903906
}
904907
restrictionsByType[es.EntityType] = r
908+
esByType[es.EntityType] = es
905909
}
906910
// Build a lookup from EDMX type qualified name → existing Mendix entity.
907911
// An entity type matches by its EntitySet name when present, otherwise by
@@ -983,13 +987,21 @@ func (e *Executor) createNavigationAssociations(
983987
assocType = domainmodel.AssociationTypeReferenceSet
984988
}
985989

986-
// Apply per-association capability defaults. For top-level
987-
// entities (entity-set source), Studio Pro defaults
988-
// UpdatableFromParent=false because link updates happen via
989-
// the foreign key on the entity, not by updating the nav
990-
// property. For contained/derived types, both default to true.
990+
// Per-association capability defaults. For a top-level FROM
991+
// entity (has its own entity set), CreatableFromParent /
992+
// UpdatableFromParent follow the entity set's Insertable /
993+
// Updatable annotations — silent metadata means the service
994+
// doesn't advertise write support, so default to false.
995+
// For contained/derived FROM entities (no entity set), both
996+
// default to true because the relationship is mutated via
997+
// the parent's write flow. Per-nav overrides from
998+
// Non{Insertable,Updatable}NavigationProperties still apply.
991999
creatable := true
992-
updatable := !parentEnt.Persistable
1000+
updatable := true
1001+
if es, ok := esByType[parentQN]; ok {
1002+
creatable = es.Insertable != nil && *es.Insertable
1003+
updatable = es.Updatable != nil && *es.Updatable
1004+
}
9931005
if r, ok := restrictionsByType[parentQN]; ok {
9941006
if r.nonInsertable[np.Name] {
9951007
creatable = false

0 commit comments

Comments
 (0)