public static ContinuationTableEntry FromEntity(Type entity) { ContinuationTableEntry entry = new ContinuationTableEntry(); entry.Type = ContinuationType.Entity; entry.Entity = entity; return(entry); }
public static ContinuationTableEntry FromProperty(PropertyInfo property, FieldAttribute field) { ContinuationTableEntry entry = new ContinuationTableEntry(); entry.Type = ContinuationType.Property; entry.Property = property; entry.FieldAttribute = field; return(entry); }
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); }
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); } }