public ForwardReference(IPersistEntity entity, ReferenceContext context, TableStore store)
 {
     Store   = store;
     _handle = new XbimInstanceHandle(entity);
     Row     = context.CurrentRow;
     Context = context;
 }
 public ForwardReference(XbimInstanceHandle handle, ReferenceContext context, TableStore store)
 {
     Store   = store;
     _handle = handle;
     Row     = context.CurrentRow;
     Context = context;
 }
        private void Join(IPersistEntity entity, ReferenceContext context,
                          Stack <IPersistEntity> parents)
        {
            var            temp = new Stack <IPersistEntity>();
            IPersistEntity parent;

            while (parents.Count != 0)
            {
                parent = parents.Pop();
                if (context.ContextType == ReferenceContextType.EntityList)
                {
                    Store.AssignEntity(parent, entity, context);
                    temp.Push(parent);
                    break;
                }

                var e = Store.ResolveContext(context.ParentContext, -1, true);
                Store.AssignEntity(e, entity, context);
                context = context.ParentContext;
                entity  = e;
                temp.Push(e);
            }

            //fill parents with the new stuff
            while (temp.Count != 0)
            {
                parent = temp.Pop();
                parents.Push(parent);
            }
        }
예제 #4
0
        internal void AssignEntity(IPersistEntity parent, IPersistEntity entity, ReferenceContext context)
        {
            if (context.MetaProperty != null && context.MetaProperty.IsDerived)
            {
                Log.WriteLine("It wasn't possible to add entity {0} as a {1} to parent {2} because it is a derived value",
                              entity.ExpressType.ExpressName, context.Segment, parent.ExpressType.ExpressName);
                return;
            }

            var index = context.Index == null ? null : new[] { context.Index };

            //inverse property
            if (context.MetaProperty != null && context.MetaProperty.IsInverse)
            {
                var remotePropName = context.MetaProperty.InverseAttributeProperty.RemoteProperty;
                var entityType     = entity.ExpressType;
                var remoteProp     = GetProperty(entityType, remotePropName);
                //it is enumerable inverse
                if (remoteProp.EnumerableType != null)
                {
                    var list = remoteProp.PropertyInfo.GetValue(entity, index) as IList;
                    if (list != null)
                    {
                        list.Add(parent);
                        return;
                    }
                }
                //it is a single inverse entity
                else
                {
                    remoteProp.PropertyInfo.SetValue(entity, parent, index);
                    return;
                }
                Log.WriteLine("It wasn't possible to add entity {0} as a {1} to parent {2}",
                              entity.ExpressType.ExpressName, context.Segment, entityType.ExpressName);
                return;
            }
            //explicit property
            var info = context.PropertyInfo;

            if (context.ContextType == ReferenceContextType.EntityList)
            {
                var list = info.GetValue(parent, index) as IList;
                if (list != null)
                {
                    list.Add(entity);
                    return;
                }
            }
            else
            {
                if ((context.MetaProperty != null && context.MetaProperty.IsExplicit) || info.GetSetMethod() != null)
                {
                    info.SetValue(parent, entity, index);
                    return;
                }
            }
            Log.WriteLine("It wasn't possible to add entity {0} as a {1} to parent {2}",
                          entity.ExpressType.ExpressName, context.Segment, parent.ExpressType.ExpressName);
        }
        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);
        }
예제 #6
0
        private ReferenceContext GetReferenceContext(ClassMapping mapping)
        {
            ReferenceContext context;

            if (_referenceContexts.TryGetValue(mapping, out context))
            {
                return(context);
            }
            context = new ReferenceContext(this, mapping);
            _referenceContexts.Add(mapping, context);
            return(context);
        }
예제 #7
0
        internal Type GetConcreteType(ReferenceContext context, ICell cell)
        {
            var cType = context.SegmentType;

            if (cType != null && !cType.Type.IsAbstract)
            {
                return(cType.Type);
            }

            //use custom type resolver if there is a one which can resolve this type
            if (cType != null && Resolvers != null && Resolvers.Any())
            {
                var resolver = Resolvers.FirstOrDefault(r => r.CanResolve(cType));
                if (resolver != null)
                {
                    return(resolver.Resolve(cType.Type, cell, context.CMapping, context.Mapping));
                }
            }

            if (context.PropertyInfo != null)
            {
                var pType = context.PropertyInfo.PropertyType;
                pType = GetNonNullableType(pType);
                if (pType.IsValueType || pType == typeof(string))
                {
                    return(pType);
                }

                if (typeof(IEnumerable).IsAssignableFrom(pType))
                {
                    pType = pType.GetGenericArguments()[0];
                    if (pType.IsValueType || pType == typeof(string))
                    {
                        return(pType);
                    }
                }

                if (Resolvers != null && Resolvers.Any())
                {
                    var resolver = Resolvers.FirstOrDefault(r => r.CanResolve(pType));
                    if (resolver != null)
                    {
                        return(resolver.Resolve(pType, cell, context.CMapping, context.Mapping));
                    }
                }
            }

            Log.WriteLine("It wasn't possible to find a non-abstract type for table {0}, class {1}",
                          context.CMapping.TableName, context.CMapping.Class);
            return(null);
        }
예제 #8
0
        /// <summary>
        /// Search the model for the entities satisfying the conditions in context
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        internal IEnumerable <IPersistEntity> GetReferencedEntities(ReferenceContext context)
        {
            var type = context.SegmentType;

            //return empty enumeration in case there are identifiers but no data
            if (context.TypeHintMapping == null && context.TableHintMapping == null && context.ScalarChildren.Any() && !context.HasData)
            {
                return(Enumerable.Empty <IPersistEntity>());
            }

            //we don't have any data so use just a type for the search
            return(!context.ScalarChildren.Any() ?
                   Model.Instances.OfType(type.Name, true) :
                   Model.Instances.OfType(type.Name, true).Where(e => IsValidEntity(context, e)));
        }
예제 #9
0
        private static bool IsValidInContext(ReferenceContext scalar, object entity)
        {
            var prop = scalar.PropertyInfo;
            var vals = scalar.Values;
            var eVal = prop.GetValue(entity, null);

            if (scalar.ContextType != ReferenceContextType.ScalarList)
            {
                return(eVal != null && vals.Any(v => v != null && v.Equals(eVal)));
            }
            var list = eVal as IEnumerable;

            return(list != null &&
                   //it might be a multivalue
                   list.Cast <object>().All(item => vals.Any(v => v.Equals(item))));
        }
예제 #10
0
        internal static bool IsValidEntity(ReferenceContext context, object entity)
        {
            if (context.ScalarChildren.Count == 0)
            {
                return(true);
            }

            //if it might have identifiers but doesn't have a one it can't find any
            if (!context.HasData)
            {
                return(false);
            }

            return(context.ScalarChildren
                   .Where(s => s.Values != null && s.Values.Length > 0)
                   .All(scalar => IsValidInContext(scalar, entity)));
        }
예제 #11
0
        private void AddMapping(PropertyMapping pMapping, List <string> segments)
        {
            if (segments == null || !segments.Any())
            {
                //this is a leaf
                Mapping = pMapping;
                return;
            }

            var segment     = segments.First();
            var segmentName = segment.Split('\\')[0];

            //handle special cases - type hints
            switch (segment)
            {
            case "[table]":
                TableHintMapping = pMapping;
                return;

            case "[type]":
                TypeHintMapping = pMapping;
                return;
            }

            var existChild = Children.FirstOrDefault(c => c.Segment == segmentName);

            if (existChild != null)
            {
                existChild.AddMapping(pMapping, segments.GetRange(1, segments.Count - 1));
            }
            else
            {
                var child = new ReferenceContext(segment, this, Store, CMapping);
                child.AddMapping(pMapping, segments.GetRange(1, segments.Count - 1));
                Children.Add(child);
                //cache scalar children for optimization
                if (child.ContextType == ReferenceContextType.Scalar || child.ContextType == ReferenceContextType.ScalarList)
                {
                    _scalarChildren.Add(child);
                }
            }
        }
예제 #12
0
        private IPersistEntity LoadFromRow(IRow row, ReferenceContext context, IRow lastRow, IPersistEntity lastEntity)
        {
            //load data into the context
            context.LoadData(row, true);

            var multirow = IsMultiRow(row, context.CMapping, lastRow);

            if (multirow)
            {
                //only add multivalue to the multivalue properties of last entity
                var subContexts = context.AllScalarChildren
                                  .Where(c => c.Mapping.MultiRow != MultiRow.None)
                                  .Select(c =>
                {
                    //get to the first list level up or on the base level if it is a scalar list
                    if (c.ContextType == ReferenceContextType.ScalarList)
                    {
                        return(c);
                    }
                    while (c != null && c.ContextType != ReferenceContextType.EntityList)
                    {
                        c = c.ParentContext;
                    }
                    return(c);
                })
                                  .Where(c => c != null)
                                  .Distinct();
                foreach (var ctx in subContexts)
                {
                    ResolveMultiContext(ctx, lastEntity);
                }
                return(lastEntity);
            }


            //get type of the coresponding object from ClassMapping or from a type hint, create instance
            return(ResolveContext(context, -1, false));
        }
예제 #13
0
        private ExpressType GetConcreteType(ReferenceContext context)
        {
            var cType = context.SegmentType;

            if (cType != null && !cType.Type.IsAbstract)
            {
                return(cType);
            }


            //use fallback to retrieve a non-abstract type (defined in a configuration file?)
            var fbTypeName = context.CMapping.FallBackConcreteType;

            if (context.IsRoot && !string.IsNullOrWhiteSpace(fbTypeName))
            {
                var eType = MetaData.ExpressType(fbTypeName.ToUpper());
                if (eType != null && !eType.Type.IsAbstract)
                {
                    return(eType);
                }
            }


            //use custom type resolver if there is a one which can resolve this type
            if (cType != null && Resolvers != null && Resolvers.Any())
            {
                var resolver = Resolvers.FirstOrDefault(r => r.CanResolve(cType));
                if (resolver != null)
                {
                    return(resolver.Resolve(cType, context, MetaData));
                }
            }

            Log.WriteLine("It wasn't possible to find a non-abstract type for table {0}, class {1}",
                          context.CMapping.TableName, context.CMapping.Class);
            return(null);
        }
예제 #14
0
        /// <summary>
        /// Returns true if it exists, FALSE if new entity fas created and needs to be filled in with data
        /// </summary>
        /// <param name="context"></param>
        /// <param name="entity"></param>
        /// <param name="type"></param>
        /// <param name="scalarIndex">Index to field of values to be used to create the key. If -1 no index is used and all values are used.</param>
        /// <returns></returns>
        private bool GetOrCreateGlobalEntity(ReferenceContext context, out IPersistEntity entity, ExpressType type, int scalarIndex)
        {
            type = type ?? GetConcreteType(context);
            Dictionary <string, IPersistEntity> entities;

            if (!_globalEntities.TryGetValue(type, out entities))
            {
                entities = new Dictionary <string, IPersistEntity>();
                _globalEntities.Add(type, entities);
            }

            var keys = scalarIndex > -1 ?
                       context.AllScalarChildren.OrderBy(c => c.Segment)
                       .Where(c => c.Values != null)
                       .Select(c =>
            {
                if (c.Values.Length == 1)
                {
                    return(c.Values[0]);
                }
                return(c.Values.Length >= scalarIndex + 1 ? c.Values[scalarIndex] : null);
            }).Where(v => v != null):

                       context.AllScalarChildren.OrderBy(c => c.Segment)
                       .Where(c => c.Values != null)
                       .SelectMany(c => c.Values.Where(cv => cv != null).Select(v => v.ToString()));
            var key = string.Join(", ", keys);

            if (entities.TryGetValue(key, out entity))
            {
                return(true);
            }

            entity = Model.Instances.New(type.Type);
            entities.Add(key, entity);
            return(false);
        }
        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);
            }
        }
예제 #16
0
        private ReferenceContext(string segment, ReferenceContext parent, TableStore store, ClassMapping cMapping)
        {
            Store    = store;
            CMapping = cMapping;

            //init lists
            Children      = new List <ReferenceContext>();
            ParentContext = parent;

            //try to extract TypeOf part of the path
            var parts = segment.Split('\\');

            segment = parts[0];
            var typeHint = parts.Length > 1 ? parts[1] : null;

            Segment = segment;

            //set up path type hint if it is defined
            if (!string.IsNullOrWhiteSpace(typeHint))
            {
                PathTypeHint = Store.MetaData.ExpressType(typeHint.ToUpper());
            }

            if (segment == "parent")
            {
                PathTypeHint = Store.MetaData.ExpressType(CMapping.ParentClass.ToUpper());
                ContextType  = ReferenceContextType.Parent;
                return;
            }

            Index        = TableStore.GetPropertyIndex(ref segment);
            PropertyInfo = Store.GetPropertyInfo(segment, parent.SegmentType, Index);
            MetaProperty = Store.GetProperty(parent.SegmentType, segment);
            var info = PropertyInfo != null
                    ? PropertyInfo.PropertyType
                    : (MetaProperty != null
                        ? MetaProperty.EnumerableType ?? MetaProperty.PropertyInfo.PropertyType
                        : null);

            if (info == null)
            {
                Store.Log.WriteLine("Type {0} doesn't have a property {1}.", parent.PathTypeHint.ExpressName, segment);
                return;
            }

            PropertyTypeHint = Store.MetaData.ExpressType(MetaProperty != null ?
                                                          MetaProperty.EnumerableType ?? MetaProperty.PropertyInfo.PropertyType :
                                                          (PropertyInfo != null ? PropertyInfo.PropertyType : null)
                                                          );


            //set up type of the context
            var isEnumerable = MetaProperty != null && MetaProperty.EnumerableType != null;

            if (isEnumerable)
            {
                if (MetaProperty.EnumerableType.IsValueType ||
                    MetaProperty.EnumerableType == typeof(string) ||
                    typeof(IExpressValueType).IsAssignableFrom(MetaProperty.EnumerableType))
                {
                    ContextType = ReferenceContextType.ScalarList;
                }
                else
                {
                    ContextType = ReferenceContextType.EntityList;
                }
            }
            else
            {
                if (info.IsValueType ||
                    info == typeof(string) ||
                    typeof(IExpressValueType).IsAssignableFrom(info))
                {
                    ContextType = ReferenceContextType.Scalar;
                }
                else
                {
                    ContextType = ReferenceContextType.Entity;
                }
            }
        }
예제 #17
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="context">Reference context of the data</param>
        /// <param name="scalarIndex">Index of value to be used in a value list in case of multi values</param>
        /// <param name="onlyScalar"></param>
        /// <returns></returns>
        internal IPersistEntity ResolveContext(ReferenceContext context, int scalarIndex, bool onlyScalar)
        {
            IPersistEntity entity = null;
            var            eType  = GetConcreteType(context);

            if (IsGlobalType(eType.Type))
            {
                //it is a global type but there are no values to fill in
                if (!context.AllScalarChildren.Any(c => c.Values != null && c.Values.Length > 0))
                {
                    return(null);
                }

                //it is a global entity and it was filled in with the data before
                if (GetOrCreateGlobalEntity(context, out entity, eType, scalarIndex))
                {
                    return(entity);
                }
            }

            //create new entity if new global one was not created
            if (entity == null)
            {
                entity = Model.Instances.New(eType.Type);
            }

            //scalar values to be set to the entity
            foreach (var scalar in context.ScalarChildren)
            {
                var values = scalar.Values;
                if (values == null || values.Length == 0)
                {
                    continue;
                }
                if (scalar.ContextType == ReferenceContextType.ScalarList)
                {
                    //is should be ItemSet which is always initialized and inherits from IList
                    var list = scalar.PropertyInfo.GetValue(entity, null) as IList;
                    if (list == null)
                    {
                        continue;
                    }
                    foreach (var value in values)
                    {
                        list.Add(value);
                    }
                    continue;
                }

                //it is a single value
                var val = scalarIndex < 0 ? values[0]: (values.Length >= scalarIndex + 1 ? values[scalarIndex] : null);
                if (val != null)
                {
                    scalar.PropertyInfo.SetValue(entity, val, scalar.Index != null ? new[] { scalar.Index } : null);
                }
            }

            if (onlyScalar)
            {
                return(entity);
            }

            //nested entities (global, local, referenced)
            foreach (var childContext in context.EntityChildren)
            {
                if (childContext.IsReference)
                {
                    _forwardReferences.Enqueue(new ForwardReference(entity, childContext, this));
                    continue;
                }

                if (childContext.ContextType == ReferenceContextType.EntityList)
                {
                    var depth =
                        childContext.ScalarChildren.Where(c => c.Values != null)
                        .Select(c => c.Values.Length)
                        .OrderByDescending(v => v)
                        .FirstOrDefault();
                    for (var i = 0; i < depth; i++)
                    {
                        var child = depth == 1 ? ResolveContext(childContext, -1, false) : ResolveContext(childContext, i, false);
                        AssignEntity(entity, child, childContext);
                    }
                    continue;
                }

                //it is a single entity
                var cEntity = ResolveContext(childContext, -1, false);
                AssignEntity(entity, cEntity, childContext);
            }

            var parentContext = context.Children.FirstOrDefault(c => c.ContextType == ReferenceContextType.Parent);

            if (parentContext != null)
            {
                _forwardReferences.Enqueue(new ForwardReference(entity, parentContext, this));
            }

            return(entity);
        }
예제 #18
0
        /// <summary>
        /// This is used for a multi-row instances where only partial context needs to be processed
        /// </summary>
        /// <param name="subContext"></param>
        /// <param name="rootEntity"></param>
        private void ResolveMultiContext(ReferenceContext subContext, IPersistEntity rootEntity)
        {
            //get context path from root entity
            var ctxStack = new Stack <ReferenceContext>();
            var context  = subContext;

            while (context != null)
            {
                ctxStack.Push(context);
                context = context.ParentContext;
            }

            //use path to get to the bottom of the stact and add the value to it
            context = ctxStack.Pop();
            var entity = rootEntity;

            //stop one level above the original subcontext
            while (ctxStack.Peek() != subContext)
            {
                //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(rootEntity, index);
                if (value == null)
                {
                    Log.WriteLine("It wasn't possible to browse to the data entry point.");
                    return;
                }

                if (context.ContextType == ReferenceContextType.Entity)
                {
                    entity = value as IPersistEntity;
                    continue;
                }

                var entities = value as IEnumerable;
                if (entities == null)
                {
                    Log.WriteLine("It wasn't possible to browse to the data entry point.");
                    return;
                }
                foreach (var e in entities)
                {
                    if (!IsValidEntity(context, e))
                    {
                        continue;
                    }
                    entity = e as IPersistEntity;
                    break;
                }
            }
            if (subContext.IsReference)
            {
                var reference = new ForwardReference(entity, subContext, this);
                _forwardReferences.Enqueue(reference);
                return;
            }

            if (subContext.ContextType == ReferenceContextType.EntityList)
            {
                var child = ResolveContext(subContext, -1, false);
                AssignEntity(entity, child, subContext);
                return;
            }

            if (subContext.ContextType == ReferenceContextType.ScalarList)
            {
                var list = subContext.PropertyInfo.GetValue(entity, null) as IList;
                if (list != null && subContext.Values != null && subContext.Values.Length > 0)
                {
                    list.Add(subContext.Values[0]);
                }
            }
        }