📄 collectionbinder.cs
字号:
using System;
using System.Collections.Generic;
using System.Xml;
using NHibernate.Mapping;
using NHibernate.Type;
using NHibernate.Util;
using Array = NHibernate.Mapping.Array;
namespace NHibernate.Cfg.XmlHbmBinding
{
public class CollectionBinder : ClassBinder
{
private readonly IDictionary<string, CreateCollectionCommand> createCollectionCommands =
new Dictionary<string, CreateCollectionCommand>();
public CollectionBinder(ClassBinder parent)
: base(parent)
{
CreateCommandCollection();
}
private void CreateCommandCollection()
{
createCollectionCommands.Add("map", CreateMap);
createCollectionCommands.Add("bag", CreateBag);
createCollectionCommands.Add("idbag", CreateIdentifierBag);
createCollectionCommands.Add("set", CreateSet);
createCollectionCommands.Add("list", CreateList);
createCollectionCommands.Add("array", CreateArray);
createCollectionCommands.Add("primitive-array", CreatePrimitiveArray);
}
public bool CanCreate(string xmlTagName)
{
return createCollectionCommands.ContainsKey(xmlTagName);
}
public Mapping.Collection Create(string xmlTagName, XmlNode node, string className,
string path, PersistentClass owner, System.Type containingType)
{
CreateCollectionCommand command = createCollectionCommands[xmlTagName];
return command(node, className, path, owner, containingType);
}
private Mapping.Collection CreateMap(XmlNode node, string prefix, string path,
PersistentClass owner, System.Type containingType)
{
Map map = new Map(owner);
BindCollection(node, map, prefix, path, containingType);
return map;
}
private Mapping.Collection CreateSet(XmlNode node, string prefix, string path,
PersistentClass owner, System.Type containingType)
{
Set setCollection = new Set(owner);
BindCollection(node, setCollection, prefix, path, containingType);
return setCollection;
}
private Mapping.Collection CreateList(XmlNode node, string prefix, string path,
PersistentClass owner, System.Type containingType)
{
List list = new List(owner);
BindCollection(node, list, prefix, path, containingType);
return list;
}
private Mapping.Collection CreateBag(XmlNode node, string prefix, string path,
PersistentClass owner, System.Type containingType)
{
Bag bag = new Bag(owner);
BindCollection(node, bag, prefix, path, containingType);
return bag;
}
private Mapping.Collection CreateIdentifierBag(XmlNode node, string prefix, string path,
PersistentClass owner, System.Type containingType)
{
IdentifierBag bag = new IdentifierBag(owner);
BindCollection(node, bag, prefix, path, containingType);
return bag;
}
private Mapping.Collection CreateArray(XmlNode node, string prefix, string path,
PersistentClass owner, System.Type containingType)
{
Array array = new Array(owner);
BindArray(node, array, prefix, path, containingType);
return array;
}
private Mapping.Collection CreatePrimitiveArray(XmlNode node, string prefix, string path,
PersistentClass owner, System.Type containingType)
{
PrimitiveArray array = new PrimitiveArray(owner);
BindArray(node, array, prefix, path, containingType);
return array;
}
/// <remarks>
/// Called for all collections. <paramref name="containingType" /> parameter
/// was added in NH to allow for reflection related to generic types.
/// </remarks>
private void BindCollection(XmlNode node, Mapping.Collection model, string className,
string path, System.Type containingType)
{
// ROLENAME
model.Role = StringHelper.Qualify(className, path);
// TODO: H3.1 has just collection.setRole(path) here - why?
XmlAttribute inverseNode = node.Attributes["inverse"];
if (inverseNode != null)
model.IsInverse = StringHelper.BooleanValue(inverseNode.Value);
// TODO: H3.1 - not ported: mutable
XmlAttribute olNode = node.Attributes["optimistic-lock"];
model.IsOptimisticLocked = olNode == null || "true".Equals(olNode.Value);
XmlAttribute orderNode = node.Attributes["order-by"];
if (orderNode != null)
model.OrderBy = orderNode.Value;
XmlAttribute whereNode = node.Attributes["where"];
if (whereNode != null)
model.Where = whereNode.Value;
XmlAttribute batchNode = node.Attributes["batch-size"];
if (batchNode != null)
model.BatchSize = int.Parse(batchNode.Value);
// PERSISTER
XmlAttribute persisterNode = node.Attributes["persister"];
if (persisterNode == null)
{
//persister = CollectionPersisterImpl.class;
}
else
model.CollectionPersisterClass = ClassForNameChecked(
persisterNode.Value, mappings,
"could not instantiate collection persister class: {0}");
XmlAttribute typeNode = node.Attributes["collection-type"];
if (typeNode != null)
model.TypeName = typeNode.Value;
// FETCH STRATEGY
InitOuterJoinFetchSetting(node, model);
if ("subselect".Equals(XmlHelper.GetAttributeValue(node, "fetch")))
{
model.IsSubselectLoadable = true;
model.Owner.HasSubselectLoadableCollections = true;
}
// LAZINESS
InitLaziness(node, model, "true", mappings.DefaultLazy);
// TODO: H3.1 - lazy="extra"
XmlNode oneToManyNode = node.SelectSingleNode(HbmConstants.nsOneToMany, namespaceManager);
if (oneToManyNode != null)
{
OneToMany oneToMany = new OneToMany(model.Owner);
model.Element = oneToMany;
BindOneToMany(oneToManyNode, oneToMany);
//we have to set up the table later!! yuck
}
else
{
//TABLE
XmlAttribute tableNode = node.Attributes["table"];
string tableName;
if (tableNode != null)
tableName = mappings.NamingStrategy.TableName(tableNode.Value);
else
tableName = mappings.NamingStrategy.PropertyToTableName(className, path);
XmlAttribute schemaNode = node.Attributes["schema"];
string schema = schemaNode == null ? mappings.SchemaName : schemaNode.Value;
XmlAttribute catalogNode = node.Attributes["catalog"];
string catalog = catalogNode == null ? mappings.CatalogName : catalogNode.Value;
model.CollectionTable = mappings.AddTable(schema, catalog, tableName, null, false);
log.InfoFormat("Mapping collection: {0} -> {1}", model.Role, model.CollectionTable.Name);
}
//SORT
XmlAttribute sortedAtt = node.Attributes["sort"];
// unsorted, natural, comparator.class.name
if (sortedAtt == null || sortedAtt.Value.Equals("unsorted"))
model.IsSorted = false;
else
{
model.IsSorted = true;
if (!sortedAtt.Value.Equals("natural"))
{
string comparatorClassName = FullClassName(sortedAtt.Value, mappings);
try
{
model.Comparer = Activator.CreateInstance(ReflectHelper.ClassForName(comparatorClassName));
}
catch
{
throw new MappingException("could not instantiate comparer class: " + comparatorClassName);
}
}
}
//ORPHAN DELETE (used for programmer error detection)
XmlAttribute cascadeAtt = node.Attributes["cascade"];
if (cascadeAtt != null && cascadeAtt.Value.Equals("all-delete-orphan"))
model.HasOrphanDelete = true;
bool? isGeneric = null;
XmlAttribute genericAtt = node.Attributes["generic"];
if (genericAtt != null)
isGeneric = bool.Parse(genericAtt.Value);
System.Type collectionType = null;
if (!isGeneric.HasValue && containingType != null)
{
collectionType = GetPropertyType(node, containingType, GetPropertyName(node));
isGeneric = collectionType.IsGenericType;
}
model.IsGeneric = isGeneric ?? false;
if (model.IsGeneric)
{
// Determine the generic arguments using reflection
if (collectionType == null)
collectionType = GetPropertyType(node, containingType, GetPropertyName(node));
System.Type[] genericArguments = collectionType.GetGenericArguments();
model.GenericArguments = genericArguments;
}
HandleCustomSQL(node, model);
//set up second pass
if (model is List)
AddListSecondPass(node, (List)model);
else if (model is Map)
AddMapSecondPass(node, (Map)model);
else if (model is Set)
AddSetSecondPass(node, (Set)model);
else if (model is IdentifierCollection)
AddIdentifierCollectionSecondPass(node, (IdentifierCollection)model);
else
AddCollectionSecondPass(node, model);
foreach (XmlNode filter in node.SelectNodes(HbmConstants.nsFilter, namespaceManager))
ParseFilter(filter, model);
XmlNode loader = node.SelectSingleNode(HbmConstants.nsLoader, namespaceManager);
if (loader != null)
model.LoaderName = XmlHelper.GetAttributeValue(loader, "query-ref");
XmlNode key = node.SelectSingleNode(HbmConstants.nsKey, namespaceManager);
if (key != null)
model.ReferencedPropertyName = XmlHelper.GetAttributeValue(key, "property-ref");
}
/// <remarks>
/// Called for arrays and primitive arrays
/// </remarks>
private void BindArray(XmlNode node, Array model, string prefix, string path,
System.Type containingType)
{
BindCollection(node, model, prefix, path, containingType);
XmlAttribute att = node.Attributes["element-class"];
if (att != null)
model.ElementClassName = GetQualifiedClassName(att.Value, mappings);
else
foreach (XmlNode subnode in node.ChildNodes)
{
// TODO NH: mmm.... the code below, maybe, must be resolved by SecondPass (not here)
string name = subnode.LocalName; //.Name;
//I am only concerned with elements that are from the nhibernate namespace
if (subnode.NamespaceURI != Configuration.MappingSchemaXMLNS)
continue;
switch (name)
{
case "element":
string typeName;
XmlAttribute typeAttribute = subnode.Attributes["type"];
if (typeAttribute != null)
typeName = typeAttribute.Value;
else
throw new MappingException("type for <element> was not defined");
IType type = TypeFactory.HeuristicType(typeName, null);
if (type == null)
throw new MappingException("could not interpret type: " + typeName);
model.ElementClassName = type.ReturnedClass.AssemblyQualifiedName;
break;
case "one-to-many":
case "many-to-many":
case "composite-element":
model.ElementClassName = GetQualifiedClassName(subnode.Attributes["class"].Value, mappings);
break;
}
}
}
private void AddListSecondPass(XmlNode node, List model)
{
mappings.AddSecondPass(delegate(IDictionary<string, PersistentClass> persistentClasses)
{
PreCollectionSecondPass(model);
BindListSecondPass(node, model, persistentClasses);
PostCollectionSecondPass(model);
});
}
private void AddMapSecondPass(XmlNode node, Map model)
{
mappings.AddSecondPass(delegate(IDictionary<string, PersistentClass> persistentClasses)
{
PreCollectionSecondPass(model);
BindMapSecondPass(node, model, persistentClasses);
PostCollectionSecondPass(model);
});
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -