internal static void GetAllColumnsAsCompositeKey(string tableName, XElement classXe, string outputNamespace) { if (UseUniqueClusteredIndexAsKey(tableName, classXe, outputNamespace)) { return; } var tbl = tableName; var compClassName = Compose.CompKeyClassName(tbl, outputNamespace); const string compPropertyName = Globals.HbmXmlNames.ID; var compKeyXeNoPk = XeFactory.CompositeIdNode(compPropertyName, compClassName); var allTblsColumns = Sorting.DbContainers.AllColumns.Data.Where(x => string.Equals(x.table_name, tbl, Sorting.C)).ToList(); var composePk = allTblsColumns.Where(x => x.is_nullable != null && x.is_nullable.Value == false).ToList(); var simpleProps = allTblsColumns.Where(x => x.is_nullable == null || x.is_nullable.Value).ToList(); if (composePk.Count <= 0) { throw new ItsDeadJim( string.Format( "The table named '{0}' has no PK, all of its columns are nullable and has no Unique Clustered Index " + "to use as a substitute - add this to the 'DoNotReference' list and try again.", tableName)); } //max is 16 when using NHibernate.Tool.hbm2ddl.SchemaExport if (composePk.Count > 16) { composePk = composePk.Take(16).ToList(); simpleProps.AddRange(composePk.Skip(16).Take(composePk.Count).ToList()); } foreach ( var simplePropXe in composePk.Select(columnData => GetSimplePropertyHbmXml(columnData, Globals.HbmXmlNames.KEY_PROPERTY))) { compKeyXeNoPk.Add(simplePropXe); } classXe.Add(compKeyXeNoPk); foreach ( var simplePropXe in simpleProps.Select(columnData => GetSimplePropertyHbmXml(columnData, Globals.HbmXmlNames.PROPERTY))) { classXe.Add(simplePropXe); } }
internal static bool UseUniqueClusteredIndexAsKey(string tableName, XElement classXe, string outputNamespace) { var tbl = tableName; //a FK reference may be set to a table with no PK if the FK references a column that is non-nullable unique non-clustered index var uqIdxColumns = Sorting.DbContainers.UniqueClusteredIdxNotPks.Data.Where( x => string.Equals(x.table_name, tbl, Sorting.C)).ToList(); if (uqIdxColumns.Count <= 0) { return(false); } var allTblsColumns = Sorting.DbContainers.AllColumns.Data.Where(x => string.Equals(x.table_name, tbl, Sorting.C)).ToList(); if (uqIdxColumns.Count == 1) { var pkId = uqIdxColumns.First(); //need to look this up in AllColumns for other bits of info var acInfo = Sorting.DbContainers.AllColumns.Data.First( x => string.Equals(x.column_name, pkId.column_name, Sorting.C)); pkId.CopyFrom(acInfo); GetSimpleId(pkId, classXe); foreach ( var simplePropXe in allTblsColumns.Where(x => !string.Equals(x.column_name, pkId.column_name)) .Select(columnData => GetSimplePropertyHbmXml(columnData, Globals.HbmXmlNames.PROPERTY))) { classXe.Add(simplePropXe); } return(true); } //although rare is is possiable to have a table with no PK and mutliple UqIdx - there is no way for the ORM to deal with this. var isIncompatiable = uqIdxColumns.Select(x => x.constraint_name).Distinct().ToList().Count > 1; if (isIncompatiable) { return(false); } var compClassName = Compose.CompKeyClassName(tbl, outputNamespace); const string compPropertyName = Globals.HbmXmlNames.ID; var compKeyXeNoPk = XeFactory.CompositeIdNode(compPropertyName, compClassName); //need to look this up in AllColumns for other bits of info foreach (var uqCol in uqIdxColumns) { var acInfo = Sorting.DbContainers.AllColumns.Data.First( x => string.Equals(x.column_name, uqCol.column_name, Sorting.C)); uqCol.CopyFrom(acInfo); } foreach ( var uqColData in uqIdxColumns.Select(columnData => GetSimplePropertyHbmXml(columnData, Globals.HbmXmlNames.KEY_PROPERTY))) { compKeyXeNoPk.Add(uqColData); } classXe.Add(compKeyXeNoPk); foreach ( var simplePropXe in allTblsColumns.Where(x => !uqIdxColumns.Any(y => string.Equals(x.column_name, y.column_name))) .Select(columnData => GetSimplePropertyHbmXml(columnData, Globals.HbmXmlNames.PROPERTY))) { classXe.Add(simplePropXe); } return(true); }
protected static bool GetPk(string outputNamespace, string tbl, Dictionary <string, PkItem> hbmPk, XElement classXe) { //----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 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(NfString.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 = NfString.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 return(hasNoPkAtAll); }