Beispiel #1
0
        public static ContinuationTableEntry FromEntity(Type entity)
        {
            ContinuationTableEntry entry = new ContinuationTableEntry();

            entry.Type   = ContinuationType.Entity;
            entry.Entity = entity;
            return(entry);
        }
Beispiel #2
0
        public static ContinuationTableEntry FromProperty(PropertyInfo property, FieldAttribute field)
        {
            ContinuationTableEntry entry = new ContinuationTableEntry();

            entry.Type           = ContinuationType.Property;
            entry.Property       = property;
            entry.FieldAttribute = field;
            return(entry);
        }
Beispiel #3
0
        public static ContinuationTableEntry FromLookup(PropertyInfo property, FieldAttribute field, PropertyInfo childProperty, FieldAttribute childField)
        {
            ContinuationTableEntry entry = new ContinuationTableEntry();

            entry.Type           = ContinuationType.Lookup;
            entry.Property       = property;
            entry.FieldAttribute = field;
            entry.Lookup         = new ContinuationTableLookupEntry()
            {
                FieldAttribute = childField, Property = childProperty
            };
            return(entry);
        }
Beispiel #4
0
        private Type BuildContinuationTable(ParameterExpression p, Expression ex, ContinuationTable table)
        {
            //
            // Only anonymous type creations can cause valid continuations.
            //
            NewExpression ne = ex as NewExpression;

            if (ne != null && IsAnonymousType(ne.Constructor.DeclaringType))
            {
                Type t = ne.Constructor.DeclaringType;

                //
                // Check for arguments that are just aliases for the entity or an entity property.
                //
                for (int i = 0; i < ne.Arguments.Count; i++)
                {
                    MemberExpression me;

                    //
                    // Get the rhs and lhs of new { <name := lhs> = <arg := rhs> }.
                    //
                    Expression   arg  = ne.Arguments[i];
                    string       name = ne.Members[i].Name.Substring("get_".Length);
                    PropertyInfo prop = t.GetProperty(name);

                    //
                    // Keep reference to the entity itself, or deal with continuation.
                    //
                    if (arg == p)
                    {
                        if (_continuationTable == null)
                        {
                            table.Add(prop, ContinuationTableEntry.FromEntity(_results.EntityType));
                        }
                        else
                        {
                            //
                            // Merge tables because there's a reference to the previous continuation type, so all original mappings are still available.
                            //
                            foreach (PropertyInfo key in _continuationTable.Keys)
                            {
                                if (!table.ContainsKey(key))
                                {
                                    table.Add(key, _continuationTable[key]);
                                }
                            }
                        }
                    }
                    //
                    // Find recursive case.
                    //
                    else if (arg is NewExpression)
                    {
                        BuildContinuationTable(p, arg, table);
                    }
                    //
                    // Find reference to entity property.
                    //
                    else if ((me = arg as MemberExpression) != null)
                    {
                        //
                        // For continuations, check whether the target is already in the table. If so, copy to the new table.
                        // This will also take care of deep copies of nested continuations if one is referred to.
                        //
                        if (_continuationTable != null)
                        {
                            //
                            // Check for raw reference.
                            //
                            PropertyInfo tgt = me.Member as PropertyInfo;
                            if (tgt != null && _continuationTable.ContainsKey(tgt))
                            {
                                table.Add(prop, _continuationTable[tgt]);
                                continue;
                            }

                            //
                            // Check for reference to anonymous type.
                            //
                            if (IsAnonymousType(tgt.PropertyType))
                            {
                                //
                                // Check in dictionary of continuations.
                                //
                                if (_continuationTables.ContainsKey(tgt.PropertyType))
                                {
                                    //
                                    // Merge tables.
                                    //
                                    foreach (PropertyInfo key in _continuationTables[tgt.PropertyType].Keys)
                                    {
                                        if (!table.ContainsKey(key))
                                        {
                                            table.Add(key, _continuationTables[tgt.PropertyType][key]);
                                        }
                                    }
                                }
                                //
                                // New nested anonymous type.
                                //
                                else
                                {
                                    Queue <Type> q = new Queue <Type>();
                                    q.Enqueue(tgt.PropertyType);
                                    while (q.Count > 0)
                                    {
                                        foreach (PropertyInfo pi in q.Dequeue().GetProperties())
                                        {
                                            //
                                            // Recursive case.
                                            //
                                            if (IsAnonymousType(pi.PropertyType))
                                            {
                                                q.Enqueue(pi.PropertyType);
                                            }
                                            //
                                            // Copy in existing references; the same key could already be present.
                                            //
                                            else if (_continuationTable.ContainsKey(pi) && !table.ContainsKey(pi))
                                            {
                                                table.Add(pi, _continuationTable[pi]);
                                            }
                                        }
                                    }
                                }
                            }
                        }

                        FieldAttribute fa;
                        PropertyInfo   target = FindEntityProperty(me, out fa);
                        if (target != null)
                        {
                            //
                            // Reference to entity property on the entity itself.
                            //
                            if (target.DeclaringType == _results.EntityType)
                            {
                                table.Add(prop, ContinuationTableEntry.FromProperty(target, fa));
                            }
                            //
                            // Lookup(Multi) fields can refer to another entity's property.
                            //
                            else
                            {
                                //
                                // Variables me2 and fa2 will refer to the parent of the current expression, which should be a lookup field on the root entity.
                                //
                                MemberExpression me2 = me.Expression as MemberExpression;
                                if (me2 != null)
                                {
                                    //
                                    // The lookup field could be referenced through a field on the previous continuation. Check for this situation.
                                    //
                                    if (_continuationTable != null)
                                    {
                                        PropertyInfo           tgt2 = me2.Member as PropertyInfo;
                                        ContinuationTableEntry el;
                                        if (tgt2 != null && _continuationTable.TryGetValue(tgt2, out el) && el.Type == ContinuationType.Property && el.Property.DeclaringType == _results.EntityType)
                                        {
                                            table.Add(prop, ContinuationTableEntry.FromLookup(el.Property, el.FieldAttribute, target, fa));
                                            continue;
                                        }
                                    }

                                    FieldAttribute fa2;
                                    PropertyInfo   target2 = FindEntityProperty(me2, out fa2);

                                    if (target2 != null && target2.DeclaringType == _results.EntityType)
                                    {
                                        table.Add(prop, ContinuationTableEntry.FromLookup(target2, fa2, target, fa));
                                    }
                                }
                            }
                        }
                    }
                }
                return(ne.Constructor.DeclaringType);
            }
            else
            {
                return(null);
            }
        }