private void ResolveParent() { if (Context.ContextType != ReferenceContextType.Parent) { return; } var cached = LastParents.Count > 0 && LastParents.All(e => { //check type var eType = e.ExpressType; if (Context.SegmentType != eType && Context.SegmentType.SubTypes.All(s => s != eType)) { return(false); } //check values return(TableStore.IsValidEntity(Context, e)); }); var parents = cached ? LastParents : Store.GetReferencedEntities(Context).ToList(); if (!parents.Any()) { Store.Log.WriteLine("There is no parent of type {0} for type {1}", Context.SegmentType.ExpressName, Entity.ExpressType.ExpressName); return; } if (parents.Count > 1) { Store.Log.WriteLine("There is more than one parent of type {0} for type {1}. All parents will be used.", Context.SegmentType.ExpressName, Entity.ExpressType.ExpressName); } var destination = Context.AllChildren.FirstOrDefault( c => !c.AllChildren.Any() && (c.ContextType == ReferenceContextType.Entity || c.ContextType == ReferenceContextType.EntityList)); if (destination == null) { Store.Log.WriteLine("There is destination path for type {1} in type {0}, table {2}.", Context.SegmentType.ExpressName, Entity.ExpressType.ExpressName, Context.CMapping.TableName); return; } foreach (var parent in parents) { AddToPath(destination, parent, Entity); } //cache parents if this was first occurance if (!cached) { LastParents.Clear(); LastParents.AddRange(parents); } }
private IPersistEntity GetFirstValid(IEnumerable <object> entities, ReferenceContext context) { var enumerable = entities as IList <object> ?? entities.ToList(); //if there is only one in the list, retun that one if (enumerable.Count == 1) { return(enumerable.First() as IPersistEntity); } if (enumerable.Count == 0) { return(null); } //if context doesn't have any data at all on any level down if (!context.HasData) { return(null); } //this context has scalar data on its level if (context.ScalarChildren.Any(c => c.Values != null && c.Values.Length > 0)) { enumerable = enumerable.Where(e => TableStore.IsValidEntity(context, e)).ToList(); //if there is only one in the list, retun that one if (enumerable.Count == 1) { return(enumerable.First() as IPersistEntity); } if (enumerable.Count == 0) { return(null); } } return(enumerable.FirstOrDefault(e => context.EntityChildren.All(c => { var index = c.Index != null ? new[] { c.Index } : null; var value = c.PropertyInfo.GetValue(e, index); //this is equivalent of contains any valid if (c.ContextType == ReferenceContextType.EntityList) { var enu = value as IEnumerable <IPersistEntity>; if (enu == null) { return false; } return GetFirstValid(enu, c) != null; } var ent = value as IPersistEntity; return ent != null && TableStore.IsValidEntity(c, ent); })) as IPersistEntity); }
private void AddToPath(ReferenceContext targetContext, IPersistEntity parent, IPersistEntity child) { //get context path from root entity var ctxStack = new Stack <ReferenceContext>(); var entityStack = new Stack <IPersistEntity>(); var context = targetContext; while (!context.IsRoot && context.ContextType != ReferenceContextType.Parent) { ctxStack.Push(context); context = context.ParentContext; } var entity = parent; while (ctxStack.Count != 0) { context = ctxStack.Pop(); entityStack.Push(entity); //browse to the level of the bottom context and call ResolveContext there var index = context.Index != null ? new[] { context.Index } : null; var value = context.PropertyInfo.GetValue(entity, index); if (context.ContextType == ReferenceContextType.Entity) { var e = value as IPersistEntity; //if it is null, create a new one or assign the child if (e == null) { e = context == targetContext ? child : Store.ResolveContext(context, -1, true); Store.AssignEntity(entity, e, context); entity = e; continue; } //verify that this is the desired one by the values. If not, create a new one on this level and higher if (TableStore.IsValidEntity(context, e)) { entity = e; continue; } //create a new one and assign it higher e = context == targetContext ? child : Store.ResolveContext(context, -1, true); Join(e, context, entityStack); entity = e; continue; } //it should be enumerable var entities = value as IEnumerable; if (entities == null) { Store.Log.WriteLine("It wasn't possible to browse to the data entry point."); return; } if (context == targetContext) { Store.AssignEntity(entity, child, context); return; } //get first valid entity entity = GetFirstValid(entities.Cast <object>(), context); //entity = entities.Cast<object>().FirstOrDefault(e => TableStore.IsValidEntity(context, e)) as IPersistEntity; if (entity != null) { continue; } //create new entity and assign it on a higher level entity = Store.ResolveContext(context, -1, true); AddToPath(context, parent, entity); } }