Detaching an Entity in LINQ to SQL

LINQ to SQL, shamelesly, does not have a Detach method, like most other O/RMs. In one particular case, I needed one - or, at least, I thought I did - so I went to write one, which wouldn't require me to use a base class. Thanks to Reflector, here's what I came up with (only tested it in version 1, not 4):


		public static void DisableAllEventHandlers(Object control)
		{
			EventDescriptorCollection ec = TypeDescriptor.GetEvents(control);

			for (Int32 i = 0; i < ec.Count; ++i)
			{
				DisableEventHandlers(control, ec[i].Name);
			}
		}

		private static FieldInfo FindField(Object obj, String fieldName)
		{
			FieldInfo fi = null;
			Type type = obj.GetType();

			while (type != null)
			{
				fi = type.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);

				if (fi != null)
				{
					break;
				}
				else
				{
					type = type.BaseType;
				}
			}

			return (fi);
		}

		private static Object FindProperty(Object obj, String propertyName)
		{
			Type type = obj.GetType();
			PropertyInfo pi = null;
			Object value = null;

			while (type != null)
			{
				pi = type.GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Instance);

				if (pi != null)
				{
					value = pi.GetValue(obj, null);
					break;
				}
				else
				{
					type = type.BaseType;
				}
			}

			return (value);
		}

		public static EventHandler DisableEventHandlers(Object control, String eventName)
		{
			FieldInfo eventFieldInfo = FindField(control, String.Concat("Event", eventName));
			EventHandler oldEventHandler = null;
			EventHandlerList eventsHandlerList = null;
			Object eventKeyObject = null;

			if (eventFieldInfo != null)
			{
				//standard process for .NET controls
				eventKeyObject = eventFieldInfo.GetValue(control);

				eventsHandlerList = FindProperty(control, "Events") as EventHandlerList;

				if ((eventKeyObject != null) && (eventsHandlerList != null))
				{
					oldEventHandler = eventsHandlerList[eventKeyObject] as EventHandler;
					eventsHandlerList[eventKeyObject] = null;
				}
			}
			else
			{
				//alternative process, for events other than the standard .NET ones
				eventFieldInfo = FindField(control, eventName);

				if (eventFieldInfo != null)
				{
					oldEventHandler = eventFieldInfo.GetValue(control) as EventHandler;
					eventFieldInfo.SetValue(control, null);
				}
			}

			return (oldEventHandler);
		}

		public Boolean IsAttached<TEntity>(TEntity entity)
		{
			Object services = typeof(DataContext).GetProperty("Services", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetProperty).GetValue(this, null);
			Object changeTracker = services.GetType().GetProperty("ChangeTracker", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetProperty).GetValue(services, null);

			Boolean isTracked = (Boolean)changeTracker.GetType().BaseType.GetMethod("IsTracked", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(changeTracker, new Object[] { entity });

			return (isTracked);
		}

		public void Detach<TEntity>(TEntity entity)
		{
			DisableAllEventHandlers(entity);

			Object services = typeof(DataContext).GetProperty("Services", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetProperty).GetValue(this, null);
			Object changeTracker = services.GetType().GetProperty("ChangeTracker", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetProperty).GetValue(services, null);
			Object identityManager = services.GetType().GetField("identifier", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic).GetValue(services);
			Object caches = identityManager.GetType().GetField("caches", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic).GetValue(identityManager);

			Object items = changeTracker.GetType().GetField("items", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(changeTracker);
			MetaType type = this.Mapping.GetMetaType(entity.GetType());

			Object existingEntity = identityManager.GetType().GetMethod("FindLike", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(identityManager, new Object[] { type, entity });

			Object trackedObject = changeTracker.GetType().GetMethod("GetTrackedObject", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(changeTracker, new Object[] { entity });

			Boolean result = (Boolean) identityManager.GetType().GetMethod("RemoveLike", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(identityManager, new Object[] { type , entity });

			Boolean isTracked = (Boolean)changeTracker.GetType().BaseType.GetMethod("IsTracked", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(changeTracker, new Object[] { entity });

			if (isTracked == true)
			{
				changeTracker.GetType().GetMethod("StopTracking", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(changeTracker, new Object[] { entity });
			}
		}
Bookmark and Share

                             

No Comments