Exemplo n.º 1
0
        /// <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);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Navigates a property path on detached instance to translate into attached instance.
        /// </summary>
        private static void NavigatePropertySet(ObjectContext context, TreeNode <ExtendedPropertyInfo> propertynode, object owner, object attachedowner)
        {
            // Try to navigate each of the properties:
            foreach (TreeNode <ExtendedPropertyInfo> childnode in propertynode.Children)
            {
                ExtendedPropertyInfo property = childnode.Item;

                // Retrieve property value:
                object related = property.PropertyInfo.GetValue(owner, null);

                if ((property.ReferenceOnly) && (typeof(IEnumerable).IsAssignableFrom(property.PropertyInfo.PropertyType)))
                {
                    // ReferenceOnly marker not valid on collections:
                    throw new InvalidOperationException("The ReferenceOnly marker method is not supported on the many side of relations.");
                }
                else if (property.ReferenceOnly)
                {
                    // Apply reference update on ReferenceOnly:
                    EntityReference reference = (EntityReference)attachedowner.PublicGetProperty(property.PropertyInfo.Name + "Reference");
                    reference.EntityKey = ((EntityReference)owner.PublicGetProperty(property.PropertyInfo.Name + "Reference")).EntityKey;
                }
                else if (related is IEnumerable)
                {
                    // Load current list in context:
                    object     attachedlist = property.PropertyInfo.GetValue(attachedowner, null);
                    RelatedEnd relatedEnd   = (RelatedEnd)attachedlist;
                    if (((EntityObject)attachedowner).EntityState != EntityState.Added && !relatedEnd.IsLoaded)
                    {
                        relatedEnd.Load();
                    }

                    // Recursively navigate through new members:
                    List <object> newlist = new List <object>();
                    foreach (var relatedinstance in (IEnumerable)related)
                    {
                        object attachedinstance = context.AddOrAttachInstance(relatedinstance, !property.NoUpdate);
                        newlist.Add(attachedinstance);
                        NavigatePropertySet(context, childnode, relatedinstance, attachedinstance);
                    }

                    // Synchronise lists:
                    List <object> removedItems;
                    SyncList(attachedlist, newlist, out removedItems);

                    // Delete removed items if association is owned:
                    if (AssociationEndBehaviorAttribute.GetAttribute(property.PropertyInfo).Owned)
                    {
                        foreach (var removedItem in removedItems)
                        {
                            context.DeleteObject(removedItem);
                        }
                    }
                }
                else if (!typeof(IEnumerable).IsAssignableFrom(property.PropertyInfo.PropertyType))
                {
                    // Load reference of currently attached in context:
                    RelatedEnd relatedEnd = (RelatedEnd)attachedowner.PublicGetProperty(property.PropertyInfo.Name + "Reference");
                    if (((EntityObject)attachedowner).EntityState != EntityState.Added && !relatedEnd.IsLoaded)
                    {
                        relatedEnd.Load();
                    }

                    // Recursively navigate through new value (unless it's null):
                    object attachedinstance;
                    if (related == null)
                    {
                        attachedinstance = null;
                    }
                    else
                    {
                        attachedinstance = context.AddOrAttachInstance(related, !property.NoUpdate);
                        NavigatePropertySet(context, childnode, related, attachedinstance);
                    }

                    // Synchronise value:
                    property.PropertyInfo.SetValue(attachedowner, attachedinstance, null);
                }
            }
        }