示例#1
0
        /// <summary>
        /// During the generation process of hbm.xml files from the various JSON metadata, it 
        /// is possiable that the names of properties may be duplicated and\or the name of 
        /// properties match their class name. 
        /// This function is intended to handle all such circumstances and correct them as needed
        /// appending a '00', '01' ,'02', etc. to the ends of duplicate names.
        /// </summary>
        /// <param name="hbmXmlOutputPath">
        /// This file must already exist on disk and, upon duplicates being found, is overwritten with the corrected contents.
        /// </param>
        /// <param name="storedProcRules">
        /// Set this flag to true if the <see cref="hbmXmlOutputPath"/>
        /// is working a file with contains any 'return-property' nodes (typically present on 
        /// sql-query nodes).
        /// </param>
        /// <remarks>
        /// This function will, in theory, work for any hbm.xml file which is of the xmlns <see cref="Globals.HBM_XML_NS"/>
        /// but was designed only for hbm.xml files generated herein.
        /// </remarks>
        public static void CorrectHbmXmlDuplicateNames(string hbmXmlOutputPath, bool storedProcRules = false)
        {
            if (!File.Exists(hbmXmlOutputPath))
                return;

            var overwriteFlag = false;

            var hbmXml = new XmlDocument();

            hbmXml.Load(hbmXmlOutputPath);

            var nsMgr = new XmlNamespaceManager(hbmXml.NameTable);
            nsMgr.AddNamespace("nhib", Globals.HBM_XML_NS);

            var hbmClassNode = hbmXml.SelectSingleNode("//nhib:class", nsMgr);
            if (hbmClassNode == null || hbmClassNode.Attributes == null)
                throw new InvalidHbmNameException(
                    string.Format(
                        "Xml file at '{0}' either does not have a node named 'class' or the 'class' node has no attributes.",
                        hbmXmlOutputPath));

            var hbmClassName = hbmClassNode.Attributes["name"].Value;
            var hbmTypeName = new Util.NfTypeName(hbmClassName);
            hbmClassName = hbmTypeName.ClassName;

            var propertyNames = new List<string>();
            var keyPropertyNames = new List<string>();
            var keyMtoPropertyNames = new List<string>();
            var returnPropNames = new List<string>();

            var propertyNodes = hbmXml.SelectNodes("//nhib:property", nsMgr);
            var manyToOneNodes = hbmXml.SelectNodes("//nhib:many-to-one", nsMgr);
            var bagNodes = hbmXml.SelectNodes("//nhib:bag", nsMgr);
            var keyPropertyNodes = hbmXml.SelectNodes("//nhib:key-property", nsMgr);
            var keyMtoPropertyNodes = hbmXml.SelectNodes("//nhib:key-many-to-one", nsMgr);
            var returnPropNodes = hbmXml.SelectNodes("//nhib:return-property", nsMgr);

            propertyNames.Add("Id");

            if (propertyNodes != null)
                propertyNames.AddRange(from XmlNode propNode in propertyNodes
                                       where propNode.Attributes != null && propNode.Attributes["name"] != null
                                       select propNode.Attributes["name"].Value);

            if (manyToOneNodes != null)
                propertyNames.AddRange(from XmlNode propNode in manyToOneNodes
                                       where propNode.Attributes != null && propNode.Attributes["name"] != null
                                       select propNode.Attributes["name"].Value);

            if (bagNodes != null)
                propertyNames.AddRange(from XmlNode propNode in bagNodes
                                       where propNode.Attributes != null && propNode.Attributes["name"] != null
                                       select propNode.Attributes["name"].Value);

            if (keyPropertyNodes != null)
                keyPropertyNames.AddRange(from XmlNode propNode in keyPropertyNodes
                                          where propNode.Attributes != null && propNode.Attributes["name"] != null
                                          select propNode.Attributes["name"].Value);

            if (keyMtoPropertyNodes != null)
                keyMtoPropertyNames.AddRange(from XmlNode propNode in keyMtoPropertyNodes
                                             where propNode.Attributes != null && propNode.Attributes["name"] != null
                                             select propNode.Attributes["name"].Value);

            if (returnPropNodes != null)
                returnPropNames.AddRange(from XmlNode propNode in returnPropNodes
                                             where propNode.Attributes != null && propNode.Attributes["name"] != null
                                             select propNode.Attributes["name"].Value);

            //acid test for duplicate names
            var dupPropOverwriteFlag = storedProcRules
                ? AcidTestDuplicateNames(hbmXmlOutputPath, propertyNames, hbmXml, nsMgr, "property")
                : AcidTestDuplicateNames(hbmXmlOutputPath, propertyNames, hbmXml, nsMgr);
            var dupKeyPropOverwriteFlag = AcidTestDuplicateNames(hbmXmlOutputPath, keyPropertyNames, hbmXml, nsMgr,
                "key-property");
            var dubMtoKeyPropOverwriteFlag = AcidTestDuplicateNames(hbmXmlOutputPath, keyMtoPropertyNames, hbmXml, nsMgr,
                "key-many-to-one");
            var dupReturnPropFlag = storedProcRules &&
                                    AcidTestDuplicateNames(hbmXmlOutputPath, returnPropNames, hbmXml, nsMgr,
                                        "return-property");

            overwriteFlag = dupKeyPropOverwriteFlag || dupPropOverwriteFlag || dubMtoKeyPropOverwriteFlag ||
                            dupReturnPropFlag;

            if (propertyNames.Contains(hbmClassName))
            {
                var pnNodes = hbmXml.SelectNodes(string.Format("//nhib:*[@name='{0}']", hbmClassName), nsMgr);
                if (pnNodes == null)
                    throw new ItsDeadJim(
                        string.Format(
                            "Property names which match the class name '{0}' are supposed to be present but an XPath selector returned null",
                            hbmClassName));
                for (var i = 0; i < pnNodes.Count; i++)
                {
                    overwriteFlag = true;
                    if (pnNodes[i] == null || pnNodes[i].Attributes == null ||
                        pnNodes[i].Attributes["name"] == null)
                        continue;
                    pnNodes[i].Attributes["name"].Value = string.Format("{0}{1:00}", hbmClassName, i);
                }
                Console.WriteLine("{0:yyyy-MM-dd HH:mm:ss.ffff}'{1}' duplicate property [{2}]", DateTime.Now,
                    hbmXmlOutputPath, hbmClassName);
            }

            if (!overwriteFlag) return;

            using (var myXmlWriter = new XmlTextWriter(hbmXmlOutputPath, System.Text.Encoding.UTF8)
            {
                Formatting = Formatting.Indented
            })
            {
                hbmXml.WriteContentTo(myXmlWriter);
                myXmlWriter.Flush();
            }
        }
示例#2
0
 public static string BagPropertyName(string fullAssemblyQualTypeName)
 {
     var pluralBagName = new Util.NfTypeName(fullAssemblyQualTypeName);
     return Util.Etymological.En.ToPlural(pluralBagName.ClassName, true);
 }
示例#3
0
        /// <summary>
        /// Produces a single hbm.xml for the given <see cref="tbl"/>
        /// </summary>
        /// <param name="outputNamespace"></param>
        /// <param name="tbl"></param>
        /// <returns>The path the generated hbm.xml file</returns>
        public static string GetSingleHbmXml(string outputNamespace, string tbl)
        {
            if(HbmKeys == null || HbmOneToMany == null || HbmBags == null)
                throw new RahRowRagee("Assign the static variables HbmKeys, HbmOneToMany and HbmBags" +
                                      " then try again (These values are calculated from Sorting).");
            if (Settings.DoNotReference.Contains(tbl))
                return null;

            var hbmPk = HbmKeys.Data;
            var hbmFk = HbmOneToMany.Data;
            var hbmBags = HbmBags.Data;

            //possiable duplicate names handled within this
            var className = Compose.ClassName(tbl, outputNamespace);

            //not having the naming pattern is exceptional
            Compose.ValidSplit(tbl, 2);

            var tableName = Util.Etc.ExtractLastWholeWord(tbl, null);
            var schemaName = tbl.Replace(string.Format(".{0}", tableName), string.Empty);

            var xe = XeFactory.HibernateMappingNode();

            var classXe = XeFactory.ClassNode(className, tableName, schemaName);

            //----PK
            var pkId = hbmPk.ContainsKey(tbl) ? hbmPk[tbl].Id : null;
            var hasNoPkAtAll = !hbmPk.ContainsKey(tbl);

            if (pkId == null && !hasNoPkAtAll)
            {
                var compClassName = Compose.CompKeyClassName(tbl, outputNamespace);
                const string compPropertyName = Globals.HbmXmlNames.ID;
                var compKeyXe = XeFactory.CompositeIdNode(compPropertyName, compClassName);

                //key-many-to-one
                var hbmKeyManyToOne = hbmPk[tbl].KeyManyToOne ?? new Dictionary<string, List<ColumnMetadata>>();
                if (hbmKeyManyToOne.Count > 0)
                {
                    foreach (var keyname in hbmKeyManyToOne.Keys.Where(k => !Settings.DoNotReference.Contains(k)))
                    {
                        //need to iterate here on a per 'constraint_name', the json data-struct misses this
                        //eg a table, 4 columns; 2 are comp to another table's Pk and the other 2 are also a comp the SAME table's PK
                        var keyManytoOneColumns = new List<ColumnMetadata>();
                        if (!HbmKeys.GetKeyManyToOneColumns(tbl, ref keyManytoOneColumns))
                            continue;
                        foreach (var distinctColumn in keyManytoOneColumns.Distinct(new ConstraintNameComparer()))
                        {
                            var dKmtoCName = distinctColumn.constraint_name;
                            var keyMtoFullyQualTypeName = Compose.ClassName(keyname, outputNamespace);
                            var keyMtoNfTypeNameObj = new Util.NfTypeName(keyMtoFullyQualTypeName);
                            var keyMtoSimpleName = keyMtoNfTypeNameObj.ClassName;

                            var keyMtoXe = XeFactory.KeyManyToOneNode(keyMtoSimpleName,
                                keyMtoFullyQualTypeName);

                            var dKmtoColumnData = hbmKeyManyToOne[keyname].Where(
                                x =>
                                    string.Equals(x.constraint_name, dKmtoCName, Sorting.C)).ToList();

                            if (dKmtoColumnData.Count <= 0)
                                continue;

                            foreach (var kmtoColumn in dKmtoColumnData)
                            {
                                kmtoColumn.CopyFrom(Sorting.GetFromAllColumnMetadata(kmtoColumn));
                                var fullColumnName = kmtoColumn.column_name;

                                //not having the naming pattern is exceptional
                                Compose.ValidSplit(fullColumnName, 3);

                                var keyMtoColumnXe =
                                    XeFactory.ColumnNode(Util.Etc.ExtractLastWholeWord(fullColumnName, null), kmtoColumn.ToJsonString());

                                keyMtoXe.Add(keyMtoColumnXe);
                            }

                            compKeyXe.Add(keyMtoXe);
                        }//end foreach distinct constraintname
                    }
                }//end key-many-to-one

                var hbmKeyProperty = hbmPk[tbl].KeyProperty ?? new Dictionary<string, List<ColumnMetadata>>();

                //these would have been added as key-many-to-one, but thier underlying table has been excluded.
                foreach (var reduced in hbmKeyManyToOne.Where(k => Settings.DoNotReference.Contains(k.Key)))
                {
                    foreach (var redux in reduced.Value)
                        redux.CopyFrom(Sorting.GetFromAllColumnMetadata(redux));//insure they got everything for being a value type

                    hbmKeyProperty.Add(reduced.Key, reduced.Value);
                }

                if (hbmKeyProperty.Count > 0)
                {
                    //Dictionary<string, List<ColumnMetadata>>
                    foreach (var keyName in hbmKeyProperty.Keys)
                    {
                        //SPECIAL NOTE: the original PS code seemed to imply that a key-property is always just one column...
                        var keyPropJsonData = hbmKeyProperty[keyName].FirstOrDefault();
                        if (keyPropJsonData == null)
                            continue;

                        keyPropJsonData.CopyFrom(Sorting.GetFromAllColumnMetadata(keyPropJsonData));
                        var keyPropPropertyName = Compose.PropertyName(keyPropJsonData.column_name);
                        var fullcolumnName = keyPropJsonData.column_name;

                        Compose.ValidSplit(fullcolumnName, 3);

                        var keyPropDataType = Util.Lexicon.Mssql2HbmTypes[(keyPropJsonData.data_type)];
                        var keyPropColumn = Util.Etc.ExtractLastWholeWord(fullcolumnName, null);
                        var keyPropLen = keyPropJsonData.string_length ?? Globals.MSSQL_MAX_VARCHAR;

                        if (string.Equals(keyPropDataType, Globals.HbmXmlNames.ANSI_STRING))
                        {
                            if (keyPropLen <= 0)
                                keyPropLen = Globals.MSSQL_MAX_VARCHAR;
                            var keyPropXe = XeFactory.KeyPropertyNode(keyPropPropertyName, keyPropColumn,
                                keyPropDataType, keyPropLen.ToString(CultureInfo.InvariantCulture), keyPropJsonData.ToJsonString());
                            compKeyXe.Add(keyPropXe);
                        }
                        else
                        {
                            var keyPropXe = XeFactory.KeyPropertyNode(keyPropPropertyName, keyPropColumn,
                                keyPropDataType, keyPropJsonData.ToJsonString());
                            compKeyXe.Add(keyPropXe);
                        }
                    }
                }
                classXe.Add(compKeyXe);
            }
            else if (pkId != null)
            {
                GetSimpleId(pkId, classXe);
            }//end PK

            //having no pk, add the contrived comp-key to the class
            if (hasNoPkAtAll)
            {
                GetAllColumnsAsCompositeKey(tbl, classXe, outputNamespace);
            }
            else//simple properties
            {
                foreach (var columnName in Sorting.DbContainers.FlatData.Data.Where(x => string.Equals(x.table_name, tbl, Sorting.C)))
                {
                    var fullColumnName = columnName.column_name;
                    Compose.ValidSplit(fullColumnName, 3);
                    var simplePropXe = GetSimplePropertyHbmXml(columnName, Globals.HbmXmlNames.PROPERTY);
                    classXe.Add(simplePropXe);
                }
            }

            //----fks which are not part of pks
            if (hbmFk.ContainsKey(tbl))
            {
                var tblFks = hbmFk[tbl].ManyToOne;
                foreach (var fkName in tblFks.Keys)
                {
                    //these would be FK ref to another type but its underlying table is excluded so now its just a bunch of value types
                    if (Settings.DoNotReference.Contains(fkName))
                    {
                        foreach (var reducedFk in tblFks[fkName])
                        {
                            var reducedFkSimpProp = GetSimplePropertyHbmXml(reducedFk,
                                Globals.HbmXmlNames.PROPERTY);
                            classXe.Add(reducedFkSimpProp);
                        }
                        continue;//these need representation but not as class types
                    }

                    var manytoOneColumns = new List<ColumnMetadata>();
                    if (!HbmOneToMany.GetManyToOneColumns(tbl, ref manytoOneColumns))
                        continue;

                    var fkColumnsByDistinctConstraintName = manytoOneColumns.Select(x => x.constraint_name).Distinct().ToList();
                    foreach (var distinctConstraintName in fkColumnsByDistinctConstraintName)
                    {
                        var dMtoColumnData = tblFks[fkName].Where(
                            x =>
                                string.Equals(x.constraint_name, distinctConstraintName, Sorting.C)).ToList();

                        if (dMtoColumnData.Count <= 0)
                            continue;
                        var fkColumnXes = new List<XElement>();
                        var fkColumnNames = new List<string>();
                        foreach (var x in dMtoColumnData)
                        {
                            x.CopyFrom(Sorting.GetFromAllColumnMetadata(x));
                            var fullColumnName = x.column_name;

                            Compose.ValidSplit(fullColumnName, 3);
                            var cn = Util.Etc.ExtractLastWholeWord(fullColumnName, null);

                            //need to store these temp, since we are also drafting thier parent's name
                            fkColumnXes.Add(XeFactory.ColumnNode(cn,x.ToJsonString()));
                            fkColumnNames.Add(cn);
                        }

                        var fkPropertyType = new Util.NfTypeName(Compose.ClassName(fkName, outputNamespace));
                        var fkPropertyName = Compose.ManyToOnePropertyName(Compose.ClassName(fkName, outputNamespace),
                            fkColumnNames.ToArray());

                        var manyToOneXe = XeFactory.ManyToOneNode(fkPropertyName, fkPropertyType.AssemblyQualifiedName);
                        foreach (var fkXe in fkColumnXes)
                            manyToOneXe.Add(fkXe);

                        classXe.Add(manyToOneXe);
                    }
                }
            }//----end Fk

            //----hbm bags
            var hbmBagNames = new List<string>(); //check for duplicates
            if (!Settings.DoNotReference.Contains(tbl) && hbmBags.ContainsKey(tbl) && !hasNoPkAtAll)
            {
                var distinctBagConstraintNames = hbmBags[tbl].Select(x => x.constraint_name).Distinct().ToList();
                foreach (var distinctBagConstraintName in distinctBagConstraintNames)
                {
                    var hbmBagPropertyName = Compose.PropertyName(distinctBagConstraintName);
                    var hbmBagXe = XeFactory.BagNode(hbmBagPropertyName, Globals.HbmXmlNames.ALL_DELETE_ORPHAN, bool.TrueString.ToLower(), bool.TrueString.ToLower(),
                        Globals.REPRESENT_512);
                    var bagColumns =
                        hbmBags[tbl].Where(x => string.Equals(x.constraint_name, distinctBagConstraintName, Sorting.C))
                            .Select(x => x.column_name)
                            .ToList();

                    string hbmOneToMany;
                    if (bagColumns.Count > 1)
                    {
                        var hbmBagFirstKey =
                            hbmBags[tbl].First(
                                x => string.Equals(x.constraint_name, distinctBagConstraintName, Sorting.C));
                        if (Settings.DoNotReference.Contains(hbmBagFirstKey.table_name))
                            continue;
                        hbmOneToMany = Compose.ClassName((hbmBagFirstKey.table_name), outputNamespace);
                        var hbmBagFkKeyXe = XeFactory.KeyNodeClassName(className);

                        foreach (
                            var columnData in
                                hbmBags[tbl].Where(
                                    x => string.Equals(x.constraint_name, distinctBagConstraintName, Sorting.C)).ToList())
                        {
                            columnData.CopyFrom(Sorting.GetFromAllColumnMetadata(columnData));
                            var fullColumnName = columnData.column_name;

                            Compose.ValidSplit(fullColumnName, 3);
                            var hbmBagKeyColumn = Util.Etc.ExtractLastWholeWord(fullColumnName, null);

                            var hbmBagKeyXe = XeFactory.ColumnNode(hbmBagKeyColumn,columnData.ToJsonString());
                            hbmBagFkKeyXe.Add(hbmBagKeyXe);
                        }

                        hbmBagXe.Add(hbmBagFkKeyXe);
                    }
                    else
                    {
                        var hbmBagFirstKey =
                            hbmBags[tbl].First(
                                x => string.Equals(x.constraint_name, distinctBagConstraintName, Sorting.C));
                        if (Settings.DoNotReference.Contains(hbmBagFirstKey.table_name))
                            continue;

                        hbmBagFirstKey.CopyFrom(Sorting.GetFromAllColumnMetadata(hbmBagFirstKey));
                        var fullColumnName = hbmBagFirstKey.column_name;
                        hbmOneToMany = Compose.ClassName((hbmBagFirstKey.table_name), outputNamespace);

                        Compose.ValidSplit(fullColumnName, 3);

                        var hbmBagKeyColumn = Util.Etc.ExtractLastWholeWord(fullColumnName, null);
                        var hbmBagKeyXe = XeFactory.KeyNodeColumnName(hbmBagKeyColumn, hbmBagFirstKey.ToJsonString());
                        hbmBagXe.Add(hbmBagKeyXe);
                    }

                    var hbmOneToManyXe = XeFactory.OneToManyNode(hbmOneToMany);
                    hbmBagXe.Add(hbmOneToManyXe);

                    //attempt to make the name plural
                    var newBagName = Compose.BagPropertyName(hbmOneToMany);
                    hbmBagXe.FirstAttribute.SetValue(newBagName);

                    classXe.Add(hbmBagXe);

                    hbmBagNames.Add(hbmBagPropertyName);
                }
            }

            xe.Add(classXe);

            var hbmXmlOutputPath = Path.Combine(Settings.HbmDirectory,
                string.Format("{0}.hbm.xml", Util.Etc.CapitalizeFirstLetterOfWholeWords(tbl, '.')));
            var xmlContent = xe.ToString()
                .Replace("<hibernate-mapping>", "<hibernate-mapping xmlns=\"urn:nhibernate-mapping-2.2\">");
            File.WriteAllText(hbmXmlOutputPath, xmlContent);

            //perform rename of any properties which match classname or are duplicated therein
            CorrectHbmXmlDuplicateNames(hbmXmlOutputPath);
            return hbmXmlOutputPath;
        }