/// <summary> /// Specifies the related objects to include in the query results using /// a lambda expression listing the path members. /// </summary> /// <returns>A new System.Data.Objects.ObjectQuery<T> with the defined query path.</returns> public static IQueryable <T> Include <T>(this IQueryable <T> query, Expression <Func <T, object> > path) { // If it's a System.Data.Objects.ObjectQuery, apply the include, otherwise ignore: if (query is ObjectQuery <T> ) { // Retrieve member path: List <ExtendedPropertyInfo> members = new List <ExtendedPropertyInfo>(); EntityFrameworkHelper.CollectRelationalMembers(path, members); // Build string path: StringBuilder sb = new StringBuilder(); string separator = ""; foreach (ExtendedPropertyInfo member in members) { if (member.ReferenceOnly) { break; } sb.Append(separator); sb.Append(member.PropertyInfo.Name); separator = "."; } // Apply Include: if (sb.Length > 0) { return(((ObjectQuery <T>)query).Include(sb.ToString())); } else { return(query); } } else { // Object is not an EF ObjectQuery: return(query); } }
/// <summary> /// Attaches multiple entire objectgraphs to the context. /// </summary> public static T[] AttachObjectGraphs <T>(this ObjectContext context, IEnumerable <T> entities, params Expression <Func <T, object> >[] paths) { T[] unattachedEntities = entities.ToArray(); T[] attachedEntities = new T[unattachedEntities.Length]; Type entityType = typeof(T); if (unattachedEntities.Length > 0) { // Workaround to ensure the assembly containing the entity type is loaded: // (see: https://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=3405138&SiteID=1) try { context.MetadataWorkspace.LoadFromAssembly(entityType.Assembly); } catch { } #region Automatic preload root entities // Create a WHERE clause for preload the root entities: StringBuilder where = new StringBuilder("(1=0)"); List <ObjectParameter> pars = new List <ObjectParameter>(); int pid = 0; foreach (T entity in unattachedEntities) { // If the entity has an entitykey: EntityKey entityKey = ((IEntityWithKey)entity).EntityKey; if (entityKey != null) { where.Append(" OR ((1=1)"); foreach (EntityKeyMember keymember in entityKey.EntityKeyValues) { string pname = String.Format("p{0}", pid++); where.Append(" AND (it.["); where.Append(keymember.Key); where.Append("] = @"); where.Append(pname); where.Append(")"); pars.Add(new ObjectParameter(pname, keymember.Value)); } where.Append(")"); } } // If WHERE clause not empty, construct and execute query: if (pars.Count > 0) { // Construct query: ObjectQuery <T> query = (ObjectQuery <T>)context.PublicGetProperty(context.GetEntitySetName(typeof(T))); foreach (var path in paths) { query = (ObjectQuery <T>)query.Include(path); } query = query.Where(where.ToString(), pars.ToArray()); // Execute query and load entities: //Console.WriteLine(query.ToTraceString()); query.Execute(MergeOption.AppendOnly).ToArray(); } #endregion Automatic preload root entities // Attach the root entities: for (int i = 0; i < unattachedEntities.Length; i++) { attachedEntities[i] = (T)context.AddOrAttachInstance(unattachedEntities[i], true); } // Collect property paths into a tree: TreeNode <ExtendedPropertyInfo> root = new TreeNode <ExtendedPropertyInfo>(null); foreach (var path in paths) { List <ExtendedPropertyInfo> members = new List <ExtendedPropertyInfo>(); EntityFrameworkHelper.CollectRelationalMembers(path, members); root.AddPath(members); } // Navigate over all properties: for (int i = 0; i < unattachedEntities.Length; i++) { NavigatePropertySet(context, root, unattachedEntities[i], attachedEntities[i]); } } // Return the attached root entities: return(attachedEntities); }