⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 defaultflushentityeventlistener.cs

📁 NHibernate NET开发者所需的
💻 CS
📖 第 1 页 / 共 2 页
字号:
using System;
using log4net;
using NHibernate.Action;
using NHibernate.Classic;
using NHibernate.Engine;
using NHibernate.Impl;
using NHibernate.Persister.Entity;
using NHibernate.Type;
using NHibernate.Util;

namespace NHibernate.Event.Default
{
	/// <summary> 
	/// An event that occurs for each entity instance at flush time 
	/// </summary>
	[Serializable]
	public class DefaultFlushEntityEventListener : IFlushEntityEventListener
	{
		private static readonly ILog log = LogManager.GetLogger(typeof(DefaultFlushEntityEventListener));

		/// <summary> 
		/// Flushes a single entity's state to the database, by scheduling an update action, if necessary
		/// </summary>
		public virtual void OnFlushEntity(FlushEntityEvent @event)
		{
			object entity = @event.Entity;
			EntityEntry entry = @event.EntityEntry;
			IEventSource session = @event.Session;
			IEntityPersister persister = entry.Persister;
			Status status = entry.Status;
			EntityMode entityMode = session.EntityMode;
			IType[] types = persister.PropertyTypes;

			bool mightBeDirty = entry.RequiresDirtyCheck(entity);

			object[] values = GetValues(entity, entry, entityMode, mightBeDirty, session);

			@event.PropertyValues = values;

			//TODO: avoid this for non-new instances where mightBeDirty==false
			bool substitute = WrapCollections(session, persister, types, values);

			if (IsUpdateNecessary(@event, mightBeDirty))
			{
				substitute = ScheduleUpdate(@event) || substitute;
			}

			if (status != Status.Deleted)
			{
				// now update the object .. has to be outside the main if block above (because of collections)
				if (substitute)
					persister.SetPropertyValues(entity, values, entityMode);

				// Search for collections by reachability, updating their role.
				// We don't want to touch collections reachable from a deleted object
				if (persister.HasCollections)
				{
					new FlushVisitor(session, entity).ProcessEntityPropertyValues(values, types);
				}
			}
		}

		private object[] GetValues(object entity, EntityEntry entry, EntityMode entityMode, bool mightBeDirty, ISessionImplementor session)
		{
			object[] loadedState = entry.LoadedState;
			Status status = entry.Status;
			IEntityPersister persister = entry.Persister;

			object[] values;
			if (status == Status.Deleted)
			{
				//grab its state saved at deletion
				values = entry.DeletedState;
			}
			else if (!mightBeDirty && loadedState != null)
			{
				values = loadedState;
			}
			else
			{
				CheckId(entity, persister, entry.Id, entityMode);

				// grab its current state
				values = persister.GetPropertyValues(entity, session.EntityMode);

				CheckNaturalId(persister, entry.Id, values, loadedState, session);
			}
			return values;
		}

		/// <summary>
		/// make sure user didn't mangle the id
		/// </summary>
		/// <param name="obj"></param>
		/// <param name="persister"></param>
		/// <param name="id"></param>
		/// <param name="entityMode"></param>
		public virtual void CheckId(object obj, IEntityPersister persister, object id, EntityMode entityMode)
		{
			if (id != null && id is DelayedPostInsertIdentifier)
			{
				// this is a situation where the entity id is assigned by a post-insert generator
				// and was saved outside the transaction forcing it to be delayed
				return;
			}

			if (persister.CanExtractIdOutOfEntity)
			{
				object oid = persister.GetIdentifier(obj, entityMode);
				if (id == null)
				{
					throw new AssertionFailure("null id in " + persister.EntityName + " entry (don't flush the Session after an exception occurs)");
				}
				if (!persister.IdentifierType.IsEqual(id, oid, EntityMode.Poco))
				{
					throw new HibernateException("identifier of an instance of " + persister.EntityName + " was altered from " + id + " to " + oid);
				}
			}
		}

		private void CheckNaturalId(IEntityPersister persister, object identifier, object[] current, object[] loaded, ISessionImplementor session)
		{
			// TODO NH: Natural Identifier
			//if (persister.HasNaturalIdentifier)
			//{
			//  if (loaded == null)
			//  {
			//    loaded = session.PersistenceContext.GetNaturalIdSnapshot(identifier, persister);
			//  }
			//  IType[] types = persister.PropertyTypes;
			//  int[] props = persister.NaturalIdentifierProperties;
			//  bool[] updateable = persister.PropertyUpdateability;
			//  for (int i = 0; i < props.Length; i++)
			//  {
			//    int prop = props[i];
			//    if (!updateable[prop])
			//    {
			//      if (!types[prop].Equals(current[prop], loaded[prop]))
			//      {
			//        throw new HibernateException("immutable natural identifier of an instance of " + persister.EntityName + " was altered");
			//      }
			//    }
			//  }
			//}
		}

		private bool WrapCollections(IEventSource session, IEntityPersister persister, IType[] types, object[] values)
		{
			if (persister.HasCollections)
			{
				// wrap up any new collections directly referenced by the object
				// or its components

				// NOTE: we need to do the wrap here even if its not "dirty",
				// because collections need wrapping but changes to _them_
				// don't dirty the container. Also, for versioned data, we
				// need to wrap before calling searchForDirtyCollections

				WrapVisitor visitor = new WrapVisitor(session);
				// substitutes into values by side-effect
				visitor.ProcessEntityPropertyValues(values, types);
				return visitor.SubstitutionRequired;
			}
			else
			{
				return false;
			}
		}

		private bool IsUpdateNecessary(FlushEntityEvent @event, bool mightBeDirty)
		{
			Status status = @event.EntityEntry.Status;
			if (mightBeDirty || status == Status.Deleted)
			{
				// compare to cached state (ignoring collections unless versioned)
				DirtyCheck(@event);
				if (IsUpdateNecessary(@event))
				{
					return true;
				}
				else
				{
					// TODO H3.2 Different behaviour
					//FieldInterceptionHelper.clearDirty(@event.Entity);
					return false;
				}
			}
			else
			{
				return HasDirtyCollections(@event, @event.EntityEntry.Persister, status);
			}
		}

		private bool ScheduleUpdate(FlushEntityEvent @event)
		{
			EntityEntry entry = @event.EntityEntry;
			IEventSource session = @event.Session;
			EntityMode entityMode = session.EntityMode;
			object entity = @event.Entity;
			Status status = entry.Status;
			IEntityPersister persister = entry.Persister;
			object[] values = @event.PropertyValues;

			if (log.IsDebugEnabled)
			{
				if (status == Status.Deleted)
				{
					log.Debug("Updating deleted entity: " + MessageHelper.InfoString(persister, entry.Id, session.Factory));
				}
				else
				{
					log.Debug("Updating entity: " + MessageHelper.InfoString(persister, entry.Id, session.Factory));
				}
			}

			bool intercepted;

			if (!entry.IsBeingReplicated)
			{
				// give the Interceptor a chance to process property values, if the properties 
				// were modified by the Interceptor, we need to set them back to the object
				intercepted = HandleInterception(@event);
			}
			else
			{
				intercepted = false;
			}

			Validate(entity, persister, status, entityMode);

			// increment the version number (if necessary)
			object nextVersion = GetNextVersion(@event);

			// if it was dirtied by a collection only
			int[] dirtyProperties = @event.DirtyProperties;
			if (@event.DirtyCheckPossible && dirtyProperties == null)
			{
				if (!intercepted && !@event.HasDirtyCollection)
				{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -