protected void InitializeValueObjectMapping() { Object writeLock = GetWriteLock(); lock (writeLock) { this.businessObjectSaveOrder = null; HashMap <Type, IISet <Type> > boTypeToBeforeBoTypes = new HashMap <Type, IISet <Type> >(); HashMap <Type, IISet <Type> > boTypeToAfterBoTypes = new HashMap <Type, IISet <Type> >(); foreach (Entry <Type, IValueObjectConfig> entry in ValueObjectMap.GetExtensions()) { IValueObjectConfig voConfig = entry.Value; Type entityType = voConfig.EntityType; Type valueType = voConfig.ValueType; IEntityMetaData metaData = GetMetaData(entityType); if (metaData == null) { // Currently no bo metadata found. We can do nothing here return; } IMap <String, ITypeInfoItem> boNameToVoMember = GetTypeInfoMapForVo(valueType); foreach (RelationMember boMember in metaData.RelationMembers) { String boMemberName = boMember.Name; String voMemberName = voConfig.GetValueObjectMemberName(boMemberName); ITypeInfoItem voMember = boNameToVoMember.Get(boMemberName); if (voConfig.IsIgnoredMember(voMemberName) || voMember == null) { continue; } Type voMemberRealType = voMember.RealType; if (voConfig.HoldsListType(voMember.Name)) { IPropertyInfo[] properties = PropertyInfoProvider.GetProperties(voMemberRealType); if (properties.Length != 1) { throw new ArgumentException("ListTypes must have exactly one property"); } voMemberRealType = TypeInfoProvider.GetMember(voMemberRealType, properties[0]).RealType; } if (!ImmutableTypeSet.IsImmutableType(voMemberRealType)) { // vo member is either a list or a single direct relation to another VO // This implies that a potential service can handle both VO types as new objects at once continue; } // vo member only holds a id reference which implies that the related VO has to be persisted first to // contain an id which can be referred to. But we do NOT know the related VO here, but we know // the related BO where ALL potential VOs will be derived from: Type boMemberElementType = boMember.ElementType; if (Object.Equals(entityType, boMemberElementType)) { continue; } AddBoTypeAfter(entityType, boMemberElementType, boTypeToBeforeBoTypes, boTypeToAfterBoTypes); AddBoTypeBefore(entityType, boMemberElementType, boTypeToBeforeBoTypes, boTypeToAfterBoTypes); } } List <Type> businessObjectSaveOrder = new List <Type>(); foreach (Type boType in boTypeToBeforeBoTypes.KeySet()) { // BeforeBoType are types which have to be saved BEFORE saving the boType bool added = false; for (int a = 0, size = businessObjectSaveOrder.Count; a < size; a++) { Type orderedBoType = businessObjectSaveOrder[a]; // OrderedBoType is the type currently inserted at the correct position in the save order - as far as the keyset // has been traversed, yet ISet <Type> typesBeforeOrderedType = boTypeToBeforeBoTypes.Get(orderedBoType); // typesBeforeOrderedType are types which have to be bool orderedHasToBeAfterCurrent = typesBeforeOrderedType != null && typesBeforeOrderedType.Contains(boType); if (!orderedHasToBeAfterCurrent) { // our boType has nothing to do with the orderedBoType. So we let is be at it is continue; } businessObjectSaveOrder.Insert(a, boType); added = true; break; } if (!added) { businessObjectSaveOrder.Add(boType); } } foreach (Type boType in boTypeToAfterBoTypes.KeySet()) { if (boTypeToBeforeBoTypes.ContainsKey(boType)) { // already handled in the previous loop continue; } bool added = false; for (int a = businessObjectSaveOrder.Count; a-- > 0;) { Type orderedBoType = businessObjectSaveOrder[a]; // OrderedBoType is the type currently inserted at the correct position in the save order - as far as the keyset // has been traversed, yet ISet <Type> typesBeforeOrderedType = boTypeToBeforeBoTypes.Get(orderedBoType); bool orderedHasToBeAfterCurrent = typesBeforeOrderedType != null && typesBeforeOrderedType.Contains(boType); if (!orderedHasToBeAfterCurrent) { // our boType has nothing to do with the orderedBoType. So we let it be as it is continue; } businessObjectSaveOrder.Insert(a, boType); added = true; break; } if (!added) { businessObjectSaveOrder.Add(boType); } } this.businessObjectSaveOrder = businessObjectSaveOrder.ToArray(); } }