classbinder.cs

来自「NHibernate NET开发者所需的」· CS 代码 · 共 1,196 行 · 第 1/3 页

CS
1,196
字号
			{
				if (subnode.Attributes["class"] == null)
					throw new MappingException("no class given for generator");

				model.IdentifierGeneratorStrategy = subnode.Attributes["class"].Value;

				Dictionary<string, string> parms = new Dictionary<string, string>();

				// NOTE: While fixing NH-1061, a couple of lines similar to the following
				// were added to ClassIdBinder.GetGeneratorProperties().  It looks like
				// we may need it here too.  But I don't want to put it in just yet.
				/* if (model.Table.Schema != null)
				    parms.Add("schema", model.Table.Schema);
				else */
				if (mappings.SchemaName != null)
					parms.Add(Id.PersistentIdGeneratorParmsNames.Schema, dialect.QuoteForSchemaName(mappings.SchemaName));

				foreach (XmlNode childNode in subnode.SelectNodes(HbmConstants.nsParam, namespaceManager))
					parms.Add(
						childNode.Attributes["name"].Value,
						childNode.InnerText
						);

				model.IdentifierGeneratorProperties = parms;
			}

			model.Table.SetIdentifierValue(model);

			//unsaved-value
			XmlAttribute nullValueNode = node.Attributes["unsaved-value"];
			if (nullValueNode != null)
				model.NullValue = nullValueNode.Value;
			else if (model.IdentifierGeneratorStrategy == "assigned")
				// TODO: H3 has model.setNullValue("undefined") here, but
				// NH doesn't (yet) allow "undefined" for id unsaved-value,
				// so we use "null" here
				model.NullValue = "null";
			else
				model.NullValue = null;
		}

		protected void BindComponent(XmlNode node, Component model, System.Type reflectedClass,
			string className, string path, bool isNullable)
		{
			XmlAttribute classNode = node.Attributes["class"];

			if ("dynamic-component".Equals(node.Name))
			{
				model.IsEmbedded = false;
				model.IsDynamic = true;
			}
			else if (classNode != null)
			{
				model.ComponentClass = ClassForNameChecked(
					classNode.Value, mappings,
					"component class not found: {0}");
				model.ComponentClassName = FullClassName(classNode.Value, mappings);
				model.IsEmbedded = false;
			}
			else if (reflectedClass != null)
			{
				model.ComponentClass = reflectedClass;
				model.IsEmbedded = false;
			}
			else
			{
				// an "embedded" component (ids only)
				model.ComponentClass = model.Owner.MappedClass;
				model.IsEmbedded = true;
			}

			foreach (XmlNode subnode in node.ChildNodes)
			{
				//I am only concerned with elements that are from the nhibernate namespace
				if (subnode.NamespaceURI != Configuration.MappingSchemaXMLNS)
					continue;

				string name = subnode.LocalName; //.Name;
				string propertyName = GetPropertyName(subnode);
				string subpath = propertyName == null ? null : StringHelper.Qualify(path, propertyName);

				IValue value = null;

				CollectionBinder binder = new CollectionBinder(this);

				if (binder.CanCreate(name))
				{
					Mapping.Collection collection = binder.Create(name, subnode, className,
						subpath, model.Owner, model.ComponentClass);

					mappings.AddCollection(collection);
					value = collection;
				}
				else if ("many-to-one".Equals(name) || "key-many-to-one".Equals(name))
				{
					value = new ManyToOne(model.Table);
					BindManyToOne(subnode, (ManyToOne) value, subpath, isNullable);
				}
				else if ("one-to-one".Equals(name))
				{
					value = new OneToOne(model.Table, model.Owner);
					BindOneToOne(subnode, (OneToOne) value);
				}
				else if ("any".Equals(name))
				{
					value = new Any(model.Table);
					BindAny(subnode, (Any) value, isNullable);
				}
				else if ("property".Equals(name) || "key-property".Equals(name))
				{
					value = new SimpleValue(model.Table);
					BindSimpleValue(subnode, (SimpleValue) value, isNullable, subpath);
				}
				else if ("component".Equals(name) || "dynamic-component".Equals(name) || "nested-composite-element".Equals(name))
				{
					System.Type subreflectedClass = model.ComponentClass == null
						?
							null
						:
							GetPropertyType(subnode, model.ComponentClass, propertyName);
					value = new Component(model);
					BindComponent(subnode, (Component) value, subreflectedClass, className, subpath, isNullable);
				}
				else if ("parent".Equals(name))
					model.ParentProperty = propertyName;

				if (value != null)
					model.AddProperty(CreateProperty(value, propertyName, model.ComponentClass, subnode));
			}
		}

		protected Mapping.Property CreateProperty(IValue value, string propertyName, System.Type parentClass,
			XmlNode subnode)
		{
			if (parentClass != null && value.IsSimpleValue)
				value.SetTypeUsingReflection(parentClass.AssemblyQualifiedName, propertyName, PropertyAccess(subnode));

			// This is done here 'cos we might only know the type here (ugly!)
			if (value is ToOne)
			{
				ToOne toOne = (ToOne) value;
				string propertyRef = toOne.ReferencedPropertyName;
				if (propertyRef != null)
					mappings.AddUniquePropertyReference(toOne.ReferencedEntityName, propertyRef);
			}

			value.CreateForeignKey();
			Mapping.Property prop = new Mapping.Property();
			prop.Value = value;
			BindProperty(subnode, prop);

			return prop;
		}

		protected void BindProperty(XmlNode node, Mapping.Property property)
		{
			string propName = XmlHelper.GetAttributeValue(node, "name");
			property.Name = propName;
			//IType type = property.Value.Type;
			//if (type == null)
			//  throw new MappingException("could not determine a property type for: " + property.Name);

			property.PropertyAccessorName = PropertyAccess(node);

			XmlAttribute cascadeNode = node.Attributes["cascade"];
			property.Cascade = (cascadeNode == null) ? mappings.DefaultCascade : cascadeNode.Value;

			XmlAttribute updateNode = node.Attributes["update"];
			property.IsUpdateable = (updateNode == null) ? true : "true".Equals(updateNode.Value);

			XmlAttribute insertNode = node.Attributes["insert"];
			property.IsInsertable = (insertNode == null) ? true : "true".Equals(insertNode.Value);

			XmlAttribute optimisticLockNode = node.Attributes["optimistic-lock"];
			property.IsOptimisticLocked = (optimisticLockNode == null) ? true : "true".Equals(optimisticLockNode.Value);

			XmlAttribute generatedNode = node.Attributes["generated"];
			string generationName = generatedNode == null ? null : generatedNode.Value;
			PropertyGeneration generation = ParsePropertyGeneration(generationName);
			property.Generation = generation;

			if (generation == PropertyGeneration.Always || generation == PropertyGeneration.Insert)
			{
				// generated properties can *never* be insertable...
				if (property.IsInsertable)
					if (insertNode == null)
						// insertable simply because that is the user did not specify
						// anything; just override it
						property.IsInsertable = false;
					else
						// the user specifically supplied insert="true",
						// which constitutes an illegal combo
						throw new MappingException(
							"cannot specify both insert=\"true\" and generated=\"" + generationName +
								"\" for property: " + propName);

				// properties generated on update can never be updateable...
				if (property.IsUpdateable && generation == PropertyGeneration.Always)
					if (updateNode == null)
						// updateable only because the user did not specify 
						// anything; just override it
						property.IsUpdateable = false;
					else
						// the user specifically supplied update="true",
						// which constitutes an illegal combo
						throw new MappingException(
							"cannot specify both update=\"true\" and generated=\"" + generationName +
								"\" for property: " + propName);
			}

			if (log.IsDebugEnabled)
			{
				string msg = "Mapped property: " + property.Name;
				string columns = Columns(property.Value);
				if (columns.Length > 0)
					msg += " -> " + columns;
				if (property.Type != null)
					msg += ", type: " + property.Type.Name;
				log.Debug(msg);
			}

			property.MetaAttributes = GetMetas(node);
		}

		protected static PropertyGeneration ParsePropertyGeneration(string name)
		{
			switch (name)
			{
				case "insert":
					return PropertyGeneration.Insert;
				case "always":
					return PropertyGeneration.Always;
				default:
					return PropertyGeneration.Never;
			}
		}

		protected static string Columns(IValue val)
		{
			StringBuilder columns = new StringBuilder();
			bool first = true;
			foreach (ISelectable col in val.ColumnIterator)
			{
				if (first)
					first = false;
				else
					columns.Append(", ");
				columns.Append(col.Text);
			}
			return columns.ToString();
		}

		//automatically makes a column with the default name if none is specified by XML
		protected void BindSimpleValue(XmlNode node, SimpleValue model, bool isNullable, string path)
		{
			BindSimpleValueType(node, model);

			BindColumnsOrFormula(node, model, path, isNullable);

			XmlAttribute fkNode = node.Attributes["foreign-key"];
			if (fkNode != null)
				model.ForeignKeyName = fkNode.Value;
		}

		private void BindSimpleValueType(XmlNode node, SimpleValue simpleValue)
		{
			string typeName = null;

			Dictionary<string, string> parameters = new Dictionary<string, string>();

			XmlAttribute typeNode = node.Attributes["type"];
			if (typeNode == null)
				typeNode = node.Attributes["id-type"]; //for an any
			if (typeNode != null)
				typeName = typeNode.Value;

			XmlNode typeChild = node.SelectSingleNode(HbmConstants.nsType, namespaceManager);
			if (typeName == null && typeChild != null)
			{
				typeName = typeChild.Attributes["name"].Value;
				foreach (XmlNode childNode in typeChild.ChildNodes)
					parameters.Add(childNode.Attributes["name"].Value, childNode.InnerText.Trim());
			}

			TypeDef typeDef = mappings.GetTypeDef(typeName);
			if (typeDef != null)
			{
				typeName = typeDef.TypeClass;
				// parameters on the property mapping should
				// override parameters in the typedef
				Dictionary<string, string> allParameters = new Dictionary<string, string>(typeDef.Parameters);
				ArrayHelper.AddAll<string, string>(allParameters, parameters);
				parameters = allParameters;
			}

			if (!(parameters.Count == 0))
				simpleValue.TypeParameters = parameters;

			if (typeName != null)
				simpleValue.TypeName = typeName;
		}

		private void BindColumnsOrFormula(XmlNode node, SimpleValue simpleValue, string path, bool isNullable)
		{
			XmlAttribute formulaNode = node.Attributes["formula"];
			if (formulaNode != null)
			{
				Formula f = new Formula();
				f.FormulaString = formulaNode.InnerText;
				simpleValue.AddFormula(f);
			}
			else
				BindColumns(node, simpleValue, isNullable, true, path);
		}

		private void AddManyToOneSecondPass(ManyToOne manyToOne)
		{
			mappings.AddSecondPass(delegate(IDictionary<string, PersistentClass> persistentClasses)
			                       	{ manyToOne.CreatePropertyRefConstraints(persistentClasses); });
		}

		protected void BindManyToOne(XmlNode node, ManyToOne model, string defaultColumnName, bool isNullable)
		{
			BindColumns(node, model, isNullable, true, defaultColumnName);
			InitOuterJoinFetchSetting(node, model);
			InitLaziness(node, model, true);

			XmlAttribute ukName = node.Attributes["property-ref"];
			if (ukName != null)
				model.ReferencedPropertyName = ukName.Value;

			model.ReferencedEntityName = GetEntityName(node, mappings);

			string notFound = XmlHelper.GetAttributeValue(node, "not-found");
			model.IsIgnoreNotFound = "ignore".Equals(notFound);

			if (ukName != null && !model.IsIgnoreNotFound)
			{
				if (!"many-to-many".Equals(node.Name))
				{
					AddManyToOneSecondPass(model);
				}
			}

			XmlAttribute fkNode = node.Attributes["foreign-key"];
			if (fkNode != null)
				model.ForeignKeyName = fkNode.Value;
		}

		protected void BindAny(XmlNode node, Any model, bool isNullable)
		{
			IType idt = GetTypeFromXML(node);
			if (idt != null)
				model.IdentifierTypeName = idt.Name;

			XmlAttribute metaAttribute = node.Attributes["meta-type"];
			if (metaAttribute != null)
			{
				model.MetaType = metaAttribute.Value;
				XmlNodeList metaValues = node.SelectNodes(HbmConstants.nsMetaValue, namespaceManager);
				if (metaValues != null && metaValues.Count > 0)
				{
					IDictionary<object, string> values = new Dictionary<object, string>();
					IType metaType = TypeFactory.HeuristicType(model.MetaType);
					foreach (XmlNode metaValue in metaValues)
						try
						{
							object value = ((IDiscriminatorType) metaType).StringToObject(metaValue.Attributes["value"].Value);
							string entityName = GetClassName(metaValue.Attributes["class"].Value, mappings);
							values[value] = entityName;
						}
						catch (InvalidCastException)
						{
							throw new MappingException("meta-type was not an IDiscriminatorType: " + metaType.Name);
						}
						catch (HibernateException he)
						{
							throw new MappingException("could not interpret meta-value", he);
						}
						catch (TypeLoadException cnfe)
						{
							throw new MappingException("meta-value class not found", cnfe);
						}
					model.MetaValues = values.Count > 0 ? values : null;
				}
			}

			BindColumns(node, model, isNullable, false, null);
		}

		private void BindOneToOne(XmlNode node, OneToOne model)
		{
			//BindColumns( node, model, isNullable, false, null, mappings );

			XmlAttribute constrNode = node.Attributes["constrained"];
			bool constrained = constrNode != null && constrNode.Value.Equals("true");
			model.IsConstrained = constrained;

			model.ForeignKeyType = (constrained

⌨️ 快捷键说明

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