PageRenderTime 27ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/Xtensive.Storage/Xtensive.Storage/Building/Builders/IndexBuilder.cs

https://bitbucket.org/Zaretto/dataobjects.net-gpl
C# | 913 lines | 781 code | 96 blank | 36 comment | 184 complexity | d268ac0516de8bd8d7bbee24c0f58ca6 MD5 | raw file
Possible License(s): AGPL-3.0
  1. // Copyright (C) 2003-2010 Xtensive LLC.
  2. // All rights reserved.
  3. // For conditions of distribution and use, see license.
  4. // Created by: Dmitri Maximov
  5. // Created: 2007.10.02
  6. using System;
  7. using System.Linq;
  8. using System.Collections.Generic;
  9. using Xtensive.Core;
  10. using Xtensive.Core.Collections;
  11. using Xtensive.Storage.Building.Definitions;
  12. using Xtensive.Storage.Model;
  13. using Xtensive.Storage.Resources;
  14. namespace Xtensive.Storage.Building.Builders
  15. {
  16. internal static partial class IndexBuilder
  17. {
  18. public static void BuildIndexes()
  19. {
  20. using (Log.InfoRegion(Strings.LogBuildingX, Strings.Indexes)) {
  21. var context = BuildingContext.Demand();
  22. CreateInterfaceIndexes();
  23. foreach (var hierarchy in context.Model.Hierarchies) {
  24. switch (hierarchy.InheritanceSchema) {
  25. case InheritanceSchema.Default:
  26. BuildClassTableIndexes(hierarchy.Root);
  27. break;
  28. case InheritanceSchema.SingleTable:
  29. BuildSingleTableIndexes(hierarchy.Root);
  30. break;
  31. case InheritanceSchema.ConcreteTable:
  32. BuildConcreteTableIndexes(hierarchy.Root);
  33. break;
  34. }
  35. }
  36. BuildInterfaceIndexes();
  37. CleanupTypedIndexes();
  38. BuildAffectedIndexes();
  39. BuildFullTextIndexes();
  40. }
  41. }
  42. #region Interface support methods
  43. private static void CreateInterfaceIndexes()
  44. {
  45. var context = BuildingContext.Demand();
  46. var processedInterfaces = new HashSet<TypeInfo>();
  47. foreach (var @interface in context.Model.Types.Find(TypeAttributes.Interface))
  48. CreateInterfaceIndexes(@interface, processedInterfaces);
  49. }
  50. private static void CreateInterfaceIndexes(TypeInfo @interface, ICollection<TypeInfo> processedInterfaces)
  51. {
  52. if (processedInterfaces.Contains(@interface))
  53. return;
  54. var context = BuildingContext.Demand();
  55. var interfaceDef = context.ModelDef.Types[@interface.UnderlyingType];
  56. // Build virtual declared interface index
  57. foreach (var indexDescriptor in interfaceDef.Indexes.Where(i => !i.IsPrimary)) {
  58. var index = BuildIndex(@interface, indexDescriptor, false);
  59. @interface.Indexes.Add(index);
  60. if (@interface.IsMaterialized)
  61. BuildingContext.Demand().Model.RealIndexes.Add(index);
  62. }
  63. var interfaces = @interface.GetInterfaces();
  64. foreach (var typeInfo in interfaces)
  65. CreateInterfaceIndexes(typeInfo, processedInterfaces);
  66. // Build virtual inherited interface index
  67. foreach (var parent in interfaces)
  68. foreach (var parentIndex in parent.Indexes.Find(IndexAttributes.Primary, MatchType.None)) {
  69. var index = BuildInheritedIndex(@interface, parentIndex, false);
  70. @interface.Indexes.Add(index);
  71. if (@interface.IsMaterialized)
  72. BuildingContext.Demand().Model.RealIndexes.Add(index);
  73. }
  74. processedInterfaces.Add(@interface);
  75. }
  76. private static void BuildInterfaceIndexes()
  77. {
  78. var context = BuildingContext.Demand();
  79. foreach (var @interface in context.Model.Types.Find(TypeAttributes.Interface)) {
  80. var implementors = @interface.GetImplementors(false).ToList();
  81. // Building primary indexes
  82. if (implementors.Count==1) {
  83. var primaryIndex = implementors[0].Indexes.PrimaryIndex;
  84. var indexView = BuildViewIndex(@interface, primaryIndex);
  85. @interface.Indexes.Add(indexView);
  86. }
  87. else {
  88. var interfaceDef = context.ModelDef.Types[@interface.UnderlyingType];
  89. var indexDef = interfaceDef.Indexes.Single(i => i.IsPrimary);
  90. var index = BuildIndex(@interface, indexDef, false);
  91. var lookup = implementors.ToLookup(t => t.Hierarchy);
  92. var underlyingIndexes = new List<IndexInfo>();
  93. foreach (var hierarchy in lookup) {
  94. var underlyingIndex = BuildIndex(@interface, indexDef, false);
  95. var hierarchyImplementors = hierarchy.ToHashSet();
  96. switch (hierarchy.Key.InheritanceSchema) {
  97. case InheritanceSchema.ClassTable: {
  98. foreach (var implementor in hierarchy) {
  99. var interfaceFields = @interface.Fields.ToHashSet();
  100. var typeIndexes = new Queue<IndexInfo>();
  101. var type = implementor;
  102. var typedIndex = (IndexInfo)null;
  103. while (interfaceFields.Count > 0) {
  104. var foundFields = new List<FieldInfo>();
  105. foreach (var field in interfaceFields) {
  106. FieldInfo typeField;
  107. if (type.FieldMap.TryGetValue(field, out typeField) && (typeField.IsDeclared || typeField.IsSystem || typeField.IsPrimaryKey))
  108. foundFields.Add(field);
  109. }
  110. if (foundFields.Count > 0) {
  111. var typeIndex = type.Indexes.FindFirst(IndexAttributes.Primary | IndexAttributes.Real);
  112. if (context.UntypedIndexes.Contains(typeIndex)) {
  113. if (type == hierarchy.Key.Root) {
  114. typeIndex = null;
  115. typedIndex = type.Indexes.Single(i => i.IsPrimary && i.IsTyped);
  116. }
  117. else {
  118. typeIndex = type.Indexes.Single(i => i.IsPrimary && !i.IsVirtual);
  119. if (typedIndex == null)
  120. typedIndex = hierarchy.Key.Root.Indexes.Single(i => i.IsPrimary && i.IsTyped);
  121. }
  122. }
  123. if (typeIndex != null)
  124. typeIndexes.Enqueue(typeIndex);
  125. foreach (var foundField in foundFields)
  126. interfaceFields.Remove(foundField);
  127. }
  128. type = type.GetAncestor();
  129. }
  130. var filterByTypes = new List<TypeInfo>();
  131. if (!implementor.IsAbstract)
  132. filterByTypes.Add(implementor);
  133. filterByTypes.AddRange(GatherDescendants(implementor, hierarchyImplementors));
  134. var indexesToJoin = new List<IndexInfo>();
  135. var filterIndex = typedIndex != null
  136. ? BuildFilterIndex(implementor, typedIndex, filterByTypes)
  137. : BuildFilterIndex(implementor, typeIndexes.Dequeue(), filterByTypes);
  138. indexesToJoin.Add(filterIndex);
  139. indexesToJoin.AddRange(typeIndexes);
  140. var indexToApplyView = indexesToJoin.Count > 1
  141. ? BuildJoinIndex(implementor, indexesToJoin)
  142. : indexesToJoin[0];
  143. var indexView = BuildViewIndex(@interface, indexToApplyView);
  144. underlyingIndex.UnderlyingIndexes.Add(indexView);
  145. }
  146. break;
  147. }
  148. case InheritanceSchema.SingleTable: {
  149. var primaryIndex = hierarchy.Key.Root.Indexes.Single(i => i.ReflectedType == hierarchy.Key.Root && i.IsPrimary && !i.IsVirtual);
  150. if (context.UntypedIndexes.Contains(primaryIndex))
  151. primaryIndex = hierarchy.Key.Root.Indexes.Single(i => i.ReflectedType == hierarchy.Key.Root && i.IsPrimary && i.IsTyped);
  152. foreach (var implementor in hierarchy) {
  153. var typesToFilter = new List<TypeInfo>();
  154. if (!implementor.IsAbstract)
  155. typesToFilter.Add(implementor);
  156. typesToFilter.AddRange(GatherDescendants(implementor, hierarchyImplementors));
  157. var filterIndex = BuildFilterIndex(implementor, primaryIndex, typesToFilter);
  158. var indexView = BuildViewIndex(@interface, filterIndex);
  159. underlyingIndex.UnderlyingIndexes.Add(indexView);
  160. }
  161. break;
  162. }
  163. case InheritanceSchema.ConcreteTable: {
  164. var grouping = hierarchy;
  165. var allImplementors = @interface.GetImplementors(true)
  166. .Where(t => t.Hierarchy == grouping.Key)
  167. .ToList();
  168. var primaryIndexes = allImplementors
  169. .Select(t => new {Index = t.Indexes.Single(i => i.IsPrimary && !i.IsVirtual), Type = t})
  170. .Select(p => context.UntypedIndexes.Contains(p.Index)
  171. ? p.Type.Indexes.Single(i => i.IsPrimary && i.IsTyped)
  172. : p.Index)
  173. .Select(i => BuildViewIndex(@interface, i));
  174. underlyingIndex.UnderlyingIndexes.AddRange(primaryIndexes);
  175. break;
  176. }
  177. }
  178. underlyingIndexes.Add(underlyingIndex);
  179. }
  180. if (underlyingIndexes.Count == 1)
  181. index = underlyingIndexes.First();
  182. else
  183. index.UnderlyingIndexes.AddRange(underlyingIndexes);
  184. @interface.Indexes.Add(index);
  185. if (@interface.IsMaterialized)
  186. BuildingContext.Demand().Model.RealIndexes.Add(index);
  187. }
  188. // Building secondary virtual indexes
  189. foreach (var interfaceIndex in @interface.Indexes.Where(i=>i.IsVirtual && !i.IsPrimary)) {
  190. var localIndex = interfaceIndex;
  191. var lookup = implementors.ToLookup(t => t.Hierarchy);
  192. var underlyingIndexes = new List<IndexInfo>();
  193. foreach (var hierarchy in lookup) {
  194. var grouping = hierarchy;
  195. var underlyingIndex = interfaceIndex.Clone();
  196. var hierarchyImplementors = hierarchy.ToHashSet();
  197. switch (hierarchy.Key.InheritanceSchema) {
  198. case InheritanceSchema.ClassTable: {
  199. foreach (var implementor in hierarchyImplementors) {
  200. var index = implementor.Indexes.SingleOrDefault(i => i.DeclaringIndex == localIndex.DeclaringIndex && !i.IsVirtual);
  201. if (index == null)
  202. throw new NotSupportedException(string.Format(Strings.ExUnableToBuildIndexXBecauseItWasBuiltOverInheritedFields, interfaceIndex.Name));
  203. var filterByTypes = new List<TypeInfo>();
  204. if (!implementor.IsAbstract)
  205. filterByTypes.Add(implementor);
  206. var subHierarchyNodeCount = implementor.GetDescendants(true).Count() + filterByTypes.Count;
  207. filterByTypes.AddRange(GatherDescendants(implementor, hierarchyImplementors));
  208. if (filterByTypes.Count != subHierarchyNodeCount)
  209. index = BuildFilterIndex(implementor, index, filterByTypes);
  210. underlyingIndex.UnderlyingIndexes.Add(index);
  211. }
  212. underlyingIndexes.Add(underlyingIndex);
  213. break;
  214. }
  215. case InheritanceSchema.SingleTable: {
  216. var rootIndexes = hierarchy.Key.Root.Indexes.Where(i => i.DeclaringIndex == localIndex.DeclaringIndex && implementors.Contains(i.ReflectedType) && !i.IsVirtual);
  217. foreach (var rootIndex in rootIndexes) {
  218. var index = context.UntypedIndexes.Contains(rootIndex)
  219. ? hierarchy.Key.Root.Indexes.Single(i => i.DeclaringIndex == localIndex.DeclaringIndex && i.ReflectedType == rootIndex.ReflectedType && i.IsTyped)
  220. : rootIndex;
  221. var filterByTypes = new List<TypeInfo>();
  222. var reflectedType = rootIndex.ReflectedType;
  223. if (!reflectedType.IsAbstract)
  224. filterByTypes.Add(reflectedType);
  225. filterByTypes.AddRange(GatherDescendants(reflectedType, hierarchyImplementors));
  226. index = BuildFilterIndex(reflectedType, index, filterByTypes);
  227. underlyingIndex.UnderlyingIndexes.Add(index);
  228. }
  229. underlyingIndexes.Add(underlyingIndex);
  230. break;
  231. }
  232. case InheritanceSchema.ConcreteTable: {
  233. var indexes = @interface.GetImplementors(true)
  234. .Where(t => t.Hierarchy == grouping.Key)
  235. .Select(t => new { Index = t.Indexes.Single(i => i.DeclaringIndex == localIndex.DeclaringIndex && !i.IsVirtual), Type = t })
  236. .Select(p => context.UntypedIndexes.Contains(p.Index)
  237. ? p.Type.Indexes.Single(i => i.DeclaringIndex == localIndex.DeclaringIndex && i.IsTyped)
  238. : p.Index);
  239. underlyingIndex.UnderlyingIndexes.AddRange(indexes);
  240. underlyingIndexes.Add(underlyingIndex);
  241. break;
  242. }
  243. }
  244. }
  245. if (underlyingIndexes.Count == 1) {
  246. var firstUnderlyingIndex = underlyingIndexes.First();
  247. interfaceIndex.Attributes = firstUnderlyingIndex.Attributes;
  248. interfaceIndex.FilterByTypes = firstUnderlyingIndex.FilterByTypes;
  249. interfaceIndex.UnderlyingIndexes.AddRange(firstUnderlyingIndex.UnderlyingIndexes);
  250. }
  251. else
  252. interfaceIndex.UnderlyingIndexes.AddRange(underlyingIndexes);
  253. }
  254. }
  255. }
  256. #endregion
  257. #region Build index methods
  258. /// <exception cref="DomainBuilderException">Something went wrong.</exception>
  259. private static IndexInfo BuildIndex(TypeInfo typeInfo, IndexDef indexDef, bool buildAbstract)
  260. {
  261. var context = BuildingContext.Demand();
  262. Log.Info(Strings.LogBuildingIndexX, indexDef.Name);
  263. var attributes = !buildAbstract ? indexDef.Attributes : indexDef.Attributes | IndexAttributes.Abstract;
  264. if (typeInfo.IsInterface && !typeInfo.IsMaterialized)
  265. attributes |= IndexAttributes.Virtual | IndexAttributes.Union;
  266. else
  267. attributes |= IndexAttributes.Real;
  268. var result = new IndexInfo(typeInfo, attributes) {
  269. FillFactor = indexDef.FillFactor,
  270. ShortName = indexDef.Name,
  271. MappingName = indexDef.MappingName
  272. };
  273. var skipTypeId = false;
  274. if (typeInfo.Hierarchy != null) {
  275. if (typeInfo.Hierarchy.InheritanceSchema == InheritanceSchema.ConcreteTable)
  276. skipTypeId = true;
  277. else if (typeInfo.Hierarchy.TypeDiscriminatorMap != null)
  278. skipTypeId = true;
  279. }
  280. if (typeInfo.Fields.Any(f => f.IsTypeId && f.IsPrimaryKey))
  281. skipTypeId = false;
  282. // Adding key columns
  283. foreach (KeyValuePair<string, Direction> pair in indexDef.KeyFields) {
  284. var fieldInfo = typeInfo.Fields[pair.Key];
  285. var columns = fieldInfo.Columns;
  286. if (columns.Count==0)
  287. throw new DomainBuilderException(
  288. string.Format(Resources.Strings.ExColumnXIsNotFound, pair.Key));
  289. foreach (var column in columns)
  290. result.KeyColumns.Add(column, pair.Value);
  291. }
  292. // Adding included columns
  293. foreach (string fieldName in indexDef.IncludedFields) {
  294. var fieldInfo = typeInfo.Fields[fieldName];
  295. var columns = fieldInfo.Columns;
  296. if (columns.Count==0)
  297. throw new DomainBuilderException(
  298. string.Format(Resources.Strings.ExColumnXIsNotFound, fieldName));
  299. foreach (var column in columns)
  300. result.IncludedColumns.Add(column);
  301. }
  302. // Adding system columns as included (only if they are not primary key or index is not primary)
  303. foreach (ColumnInfo column in typeInfo.Columns.Find(ColumnAttributes.System).Where(c => indexDef.IsPrimary ? !c.IsPrimaryKey : true)) {
  304. if (skipTypeId && column.IsSystem && column.Field.IsTypeId)
  305. continue;
  306. result.IncludedColumns.Add(column);
  307. }
  308. // Adding value columns
  309. if (indexDef.IsPrimary) {
  310. IEnumerable<TypeInfo> types;
  311. if (typeInfo.IsInterface)
  312. types = typeInfo.GetInterfaces().Union(new[] { typeInfo });
  313. else {
  314. var root = typeInfo.Hierarchy.Root;
  315. var schema = typeInfo.Hierarchy.InheritanceSchema;
  316. switch (schema) {
  317. case InheritanceSchema.SingleTable:
  318. types = new[] {typeInfo}.Union(root.GetDescendants(true));
  319. break;
  320. case InheritanceSchema.ConcreteTable:
  321. types = typeInfo.GetAncestors().Union(new[] {typeInfo});
  322. break;
  323. default:
  324. types = new[] {typeInfo};
  325. break;
  326. }
  327. }
  328. var columns = new List<ColumnInfo>();
  329. columns.AddRange(result.IncludedColumns);
  330. columns.AddRange(types.SelectMany(t => t.Columns
  331. .Find(ColumnAttributes.Inherited | ColumnAttributes.PrimaryKey, MatchType.None)
  332. .Where(c => skipTypeId ? !(c.Field.IsTypeId && c.IsSystem) : true)));
  333. result.ValueColumns.AddRange(GatherValueColumns(columns));
  334. }
  335. else {
  336. foreach (var column in typeInfo.Columns.Where(c => c.IsPrimaryKey)) {
  337. if (!result.KeyColumns.ContainsKey(column))
  338. result.ValueColumns.Add(column);
  339. }
  340. result.ValueColumns.AddRange(result.IncludedColumns.Where(ic => !result.ValueColumns.Contains(ic.Name)));
  341. }
  342. result.Name = context.NameBuilder.BuildIndexName(typeInfo, result);
  343. result.Group = BuildColumnGroup(result);
  344. if (skipTypeId)
  345. context.UntypedIndexes.Add(result);
  346. return result;
  347. }
  348. private static IndexInfo BuildInheritedIndex(TypeInfo reflectedType, IndexInfo ancestorIndex, bool buildAbstract)
  349. {
  350. Log.Info(Strings.LogBuildingIndexX, ancestorIndex.Name);
  351. var attributes = IndexAttributes.None;
  352. if (reflectedType.IsInterface && !reflectedType.IsMaterialized)
  353. attributes = (ancestorIndex.Attributes | IndexAttributes.Virtual | IndexAttributes.Union) &
  354. ~(IndexAttributes.Real | IndexAttributes.Join | IndexAttributes.Filtered);
  355. else
  356. attributes = (ancestorIndex.Attributes | IndexAttributes.Real)
  357. & ~(IndexAttributes.Join | IndexAttributes.Union | IndexAttributes.Filtered | IndexAttributes.Virtual | IndexAttributes.Abstract);
  358. if (buildAbstract)
  359. attributes = attributes | IndexAttributes.Abstract;
  360. var result = new IndexInfo(reflectedType, attributes, ancestorIndex);
  361. var useFieldMap = ancestorIndex.ReflectedType.IsInterface && !reflectedType.IsInterface;
  362. var skipTypeId = false;
  363. if (reflectedType.Hierarchy != null) {
  364. if (reflectedType.Hierarchy.InheritanceSchema == InheritanceSchema.ConcreteTable)
  365. skipTypeId = true;
  366. else if (reflectedType.Hierarchy.TypeDiscriminatorMap != null)
  367. skipTypeId = true;
  368. }
  369. if (reflectedType.Fields.Any(f => f.IsTypeId && f.IsPrimaryKey))
  370. skipTypeId = false;
  371. // Adding key columns
  372. foreach (KeyValuePair<ColumnInfo, Direction> pair in ancestorIndex.KeyColumns) {
  373. var field = useFieldMap ?
  374. reflectedType.FieldMap[pair.Key.Field] :
  375. reflectedType.Fields[pair.Key.Field.Name];
  376. result.KeyColumns.Add(field.Column, pair.Value);
  377. }
  378. // Adding included columns
  379. foreach (var column in ancestorIndex.IncludedColumns) {
  380. if (skipTypeId && column.IsSystem && column.Field.IsTypeId)
  381. continue;
  382. var field = useFieldMap ?
  383. reflectedType.FieldMap[column.Field] :
  384. reflectedType.Fields[column.Field.Name];
  385. result.IncludedColumns.Add(field.Column);
  386. }
  387. // Adding value columns
  388. if (!ancestorIndex.IsPrimary)
  389. foreach (var column in ancestorIndex.ValueColumns) {
  390. if (skipTypeId && column.IsSystem && column.Field.IsTypeId)
  391. continue;
  392. var field = useFieldMap ?
  393. reflectedType.FieldMap[column.Field] :
  394. reflectedType.Fields[column.Field.Name];
  395. result.ValueColumns.Add(field.Column);
  396. }
  397. else if (reflectedType.IsMaterialized)
  398. result.ValueColumns.AddRange(reflectedType.Columns
  399. .Find(ColumnAttributes.PrimaryKey, MatchType.None)
  400. .Where(c => skipTypeId ? !(c.IsSystem && c.Field.IsTypeId) : true));
  401. if (ancestorIndex.IsPrimary && reflectedType.IsEntity) {
  402. if (reflectedType.Hierarchy.InheritanceSchema==InheritanceSchema.ClassTable) {
  403. foreach (var column in ancestorIndex.IncludedColumns) {
  404. if (skipTypeId && column.IsSystem && column.Field.IsTypeId)
  405. continue;
  406. var field = reflectedType.Fields[column.Field.Name];
  407. result.ValueColumns.Add(field.Column);
  408. }
  409. foreach (var column in reflectedType.Columns.Find(ColumnAttributes.Inherited | ColumnAttributes.PrimaryKey, MatchType.None)) {
  410. if (skipTypeId && column.IsSystem && column.Field.IsTypeId)
  411. continue;
  412. result.ValueColumns.Add(column);
  413. }
  414. }
  415. else if (reflectedType.Hierarchy.InheritanceSchema==InheritanceSchema.ConcreteTable) {
  416. foreach (var column in reflectedType.Columns.Find(ColumnAttributes.PrimaryKey, MatchType.None)) {
  417. if (skipTypeId && column.IsSystem && column.Field.IsTypeId)
  418. continue;
  419. if (!result.ValueColumns.Contains(column.Name))
  420. result.ValueColumns.Add(column);
  421. }
  422. }
  423. }
  424. var context = BuildingContext.Demand();
  425. result.Name = context.NameBuilder.BuildIndexName(reflectedType, result);
  426. result.Group = BuildColumnGroup(result);
  427. if (skipTypeId)
  428. context.UntypedIndexes.Add(result);
  429. return result;
  430. }
  431. #endregion
  432. #region Build virtual index methods
  433. private static IndexInfo BuildTypedIndex(TypeInfo reflectedType, IndexInfo realIndex)
  434. {
  435. if (realIndex.IsVirtual)
  436. throw new InvalidOperationException();
  437. var nameBuilder = BuildingContext.Demand().NameBuilder;
  438. var attributes = realIndex.Attributes
  439. & (IndexAttributes.Primary | IndexAttributes.Secondary | IndexAttributes.Unique)
  440. | IndexAttributes.Typed | IndexAttributes.Virtual;
  441. var result = new IndexInfo(reflectedType, attributes, realIndex, ArrayUtils<IndexInfo>.EmptyArray);
  442. // Adding key columns
  443. foreach (KeyValuePair<ColumnInfo, Direction> pair in realIndex.KeyColumns) {
  444. var field = reflectedType.Fields[pair.Key.Field.Name];
  445. result.KeyColumns.Add(field.Column, pair.Value);
  446. }
  447. // Adding included columns
  448. foreach (var column in realIndex.IncludedColumns) {
  449. var field = reflectedType.Fields[column.Field.Name];
  450. result.IncludedColumns.Add(field.Column);
  451. }
  452. // Adding TypeId column
  453. if (realIndex.IsPrimary)
  454. result.ValueColumns.Add(reflectedType.Columns.Single(c => c.IsSystem && c.Field.IsTypeId));
  455. // Adding value columns
  456. result.ValueColumns.AddRange(realIndex.ValueColumns);
  457. // Adding TypeId column
  458. if (!realIndex.IsPrimary)
  459. result.ValueColumns.Add(reflectedType.Columns.Single(c => c.IsSystem && c.Field.IsTypeId));
  460. result.Name = nameBuilder.BuildIndexName(reflectedType, result);
  461. result.Group = BuildColumnGroup(result);
  462. return result;
  463. }
  464. private static IndexInfo BuildFilterIndex(TypeInfo reflectedType, IndexInfo indexToFilter, IEnumerable<TypeInfo> filterByTypes)
  465. {
  466. var nameBuilder = BuildingContext.Demand().NameBuilder;
  467. var attributes = indexToFilter.Attributes
  468. & (IndexAttributes.Primary | IndexAttributes.Secondary | IndexAttributes.Unique )
  469. | IndexAttributes.Filtered | IndexAttributes.Virtual;
  470. var result = new IndexInfo(reflectedType, attributes, indexToFilter, ArrayUtils<IndexInfo>.EmptyArray) {FilterByTypes = filterByTypes.ToList()};
  471. // Adding key columns
  472. foreach (KeyValuePair<ColumnInfo, Direction> pair in indexToFilter.KeyColumns) {
  473. var field = reflectedType.Fields[pair.Key.Field.Name];
  474. result.KeyColumns.Add(field.Column, pair.Value);
  475. }
  476. // Adding included columns
  477. foreach (var column in indexToFilter.IncludedColumns) {
  478. var field = reflectedType.Fields[column.Field.Name];
  479. result.IncludedColumns.Add(field.Column);
  480. }
  481. // Adding value columns
  482. result.ValueColumns.AddRange(indexToFilter.ValueColumns);
  483. result.Name = nameBuilder.BuildIndexName(reflectedType, result);
  484. result.Group = BuildColumnGroup(result);
  485. return result;
  486. }
  487. private static IndexInfo BuildJoinIndex(TypeInfo reflectedType, IEnumerable<IndexInfo> indexesToJoin)
  488. {
  489. var nameBuilder = BuildingContext.Demand().NameBuilder;
  490. var firstIndex = indexesToJoin.First();
  491. var otherIndexes = indexesToJoin.Skip(1).ToArray();
  492. var attributes = firstIndex.Attributes
  493. & (IndexAttributes.Primary | IndexAttributes.Secondary | IndexAttributes.Unique )
  494. | IndexAttributes.Join | IndexAttributes.Virtual;
  495. var result = new IndexInfo(reflectedType, attributes, firstIndex, otherIndexes);
  496. // Adding key columns
  497. foreach (KeyValuePair<ColumnInfo, Direction> pair in firstIndex.KeyColumns) {
  498. var field = reflectedType.Fields[pair.Key.Field.Name];
  499. result.KeyColumns.Add(field.Column, pair.Value);
  500. }
  501. // Adding included columns
  502. foreach (var column in firstIndex.IncludedColumns) {
  503. var field = reflectedType.Fields[column.Field.Name];
  504. result.IncludedColumns.Add(field.Column);
  505. }
  506. // Adding value columns
  507. var typeOrder = reflectedType.GetAncestors()
  508. .AddOne(reflectedType)
  509. .Select((t, i) => new {Type = t, Index = i})
  510. .ToDictionary(a => a.Type, a => a.Index);
  511. var types = reflectedType.GetAncestors()
  512. .AddOne(reflectedType)
  513. .ToHashSet();
  514. var valueColumnMap = new List<List<int>>();
  515. foreach (var index in indexesToJoin) {
  516. var columnMap = new List<int>();
  517. int columnIndex = -1;
  518. foreach (var column in index.ValueColumns) {
  519. columnIndex++;
  520. if (columnIndex < result.IncludedColumns.Count)
  521. continue;
  522. var field = column.Field;
  523. if (!types.Contains(field.DeclaringType))
  524. continue;
  525. if (field.IsExplicit) {
  526. var ancestor = reflectedType;
  527. var skip = false;
  528. while (ancestor != field.DeclaringType) {
  529. FieldInfo ancestorField;
  530. if (ancestor.Fields.TryGetValue(field.Name, out ancestorField))
  531. skip = ancestorField.IsDeclared;
  532. if (skip)
  533. break;
  534. ancestor = ancestor.GetAncestor();
  535. }
  536. if (skip)
  537. continue;
  538. }
  539. columnMap.Add(columnIndex);
  540. }
  541. valueColumnMap.Add(columnMap);
  542. }
  543. var orderedIndexes = indexesToJoin
  544. .Select((index, i) => new {index, columns = valueColumnMap[i], i})
  545. .OrderBy(a => typeOrder[a.index.ValueColumns.First().Field.ReflectedType])
  546. .ToList();
  547. var columnsToAdd = new List<ColumnInfo>();
  548. var valueColumnMapping = new List<Pair<int, List<int>>>();
  549. for (var i = 0; i < orderedIndexes.Count; i++) {
  550. var item = orderedIndexes[i];
  551. if (valueColumnMapping.Count == 0)
  552. item.columns.InsertRange(0, Enumerable.Range(0, result.IncludedColumns.Count));
  553. foreach (var columnIndex in item.columns) {
  554. var column = item.index.ValueColumns[columnIndex];
  555. columnsToAdd.Add(column);
  556. }
  557. valueColumnMapping.Add(new Pair<int, List<int>>(item.i, item.columns));
  558. }
  559. result.ValueColumnsMap = valueColumnMapping;
  560. result.ValueColumns.AddRange(GatherValueColumns(columnsToAdd));
  561. result.Name = nameBuilder.BuildIndexName(reflectedType, result);
  562. result.Group = BuildColumnGroup(result);
  563. return result;
  564. }
  565. private static IndexInfo BuildUnionIndex(TypeInfo reflectedType, IEnumerable<IndexInfo> indexesToUnion)
  566. {
  567. var nameBuilder = BuildingContext.Demand().NameBuilder;
  568. var firstIndex = indexesToUnion.First();
  569. var otherIndexes = indexesToUnion.Skip(1).ToArray();
  570. var attributes = firstIndex.Attributes
  571. & (IndexAttributes.Primary | IndexAttributes.Secondary | IndexAttributes.Unique )
  572. | IndexAttributes.Union | IndexAttributes.Virtual;
  573. var result = new IndexInfo(reflectedType, attributes, firstIndex, otherIndexes);
  574. // Adding key columns
  575. foreach (KeyValuePair<ColumnInfo, Direction> pair in firstIndex.KeyColumns) {
  576. var field = reflectedType.Fields[pair.Key.Field.Name];
  577. result.KeyColumns.Add(field.Column, pair.Value);
  578. }
  579. // Adding included columns
  580. foreach (var column in firstIndex.IncludedColumns) {
  581. var field = reflectedType.Fields[column.Field.Name];
  582. result.IncludedColumns.Add(field.Column);
  583. }
  584. // Adding value columns
  585. result.ValueColumns.AddRange(firstIndex.ValueColumns);
  586. result.Name = nameBuilder.BuildIndexName(reflectedType, result);
  587. result.Group = BuildColumnGroup(result);
  588. foreach (var index in indexesToUnion)
  589. if ((index.Attributes & IndexAttributes.Abstract) == IndexAttributes.Abstract)
  590. result.UnderlyingIndexes.Remove(index);
  591. return result;
  592. }
  593. private static IndexInfo BuildViewIndex(TypeInfo reflectedType, IndexInfo indexToApplyView)
  594. {
  595. var nameBuilder = BuildingContext.Demand().NameBuilder;
  596. var attributes = indexToApplyView.Attributes
  597. & (IndexAttributes.Primary | IndexAttributes.Secondary | IndexAttributes.Unique )
  598. | IndexAttributes.View | IndexAttributes.Virtual;
  599. var result = new IndexInfo(reflectedType, attributes, indexToApplyView, ArrayUtils<IndexInfo>.EmptyArray);
  600. // Adding key columns
  601. foreach (KeyValuePair<ColumnInfo, Direction> pair in indexToApplyView.KeyColumns) {
  602. var field = reflectedType.Fields[pair.Key.Field.Name];
  603. result.KeyColumns.Add(field.Column, pair.Value);
  604. }
  605. // Adding included columns
  606. foreach (var column in indexToApplyView.IncludedColumns) {
  607. var field = reflectedType.Fields[column.Field.Name];
  608. result.IncludedColumns.Add(field.Column);
  609. }
  610. // Adding value columns
  611. var types = (reflectedType.IsInterface
  612. ? indexToApplyView.ReflectedType.GetAncestors().AddOne(indexToApplyView.ReflectedType)
  613. : reflectedType.GetAncestors().AddOne(reflectedType)).ToHashSet();
  614. var interfaces = (reflectedType.IsInterface
  615. ? reflectedType.GetInterfaces(true).AddOne(reflectedType)
  616. : Enumerable.Empty<TypeInfo>()).ToHashSet();
  617. var indexReflectedType = indexToApplyView.ReflectedType;
  618. var keyLength = indexToApplyView.KeyColumns.Count;
  619. var columnMap = new List<int>();
  620. var valueColumns = new List<ColumnInfo>(reflectedType.Columns.Count);
  621. for (int i = 0; i < indexToApplyView.ValueColumns.Count; i++) {
  622. var column = indexToApplyView.ValueColumns[i];
  623. var columnField = column.Field;
  624. var declaringType = columnField.DeclaringType;
  625. if (!types.Contains(declaringType))
  626. continue;
  627. if (reflectedType.IsInterface) {
  628. if (!columnField.IsInterfaceImplementation)
  629. continue;
  630. var interfaceFields = indexReflectedType.FieldMap.GetImplementedInterfaceFields(columnField);
  631. var interfaceField = interfaceFields.FirstOrDefault(f => interfaces.Contains(f.DeclaringType));
  632. if (interfaceField == null)
  633. continue;
  634. var field = reflectedType.Fields[interfaceField.Name];
  635. valueColumns.Add(field.Column);
  636. }
  637. else {
  638. if (columnField.IsExplicit) {
  639. var ancestor = reflectedType;
  640. var skip = false;
  641. while (ancestor != columnField.DeclaringType ) {
  642. FieldInfo ancestorField;
  643. if (ancestor.Fields.TryGetValue(columnField.Name, out ancestorField))
  644. skip = ancestorField.IsDeclared;
  645. if (skip)
  646. break;
  647. ancestor = ancestor.GetAncestor();
  648. }
  649. if (skip)
  650. continue;
  651. }
  652. var field = reflectedType.Fields[columnField.Name];
  653. valueColumns.Add(field.Column);
  654. }
  655. columnMap.Add(keyLength + i);
  656. }
  657. var actualColumnMapping = valueColumns
  658. .Zip(columnMap, (column, sourceIndex) => new {column, sourceIndex})
  659. .OrderBy(p => reflectedType.Columns.IndexOf(p.column))
  660. .ToList();
  661. valueColumns.Clear();
  662. columnMap.Clear();
  663. columnMap.AddRange(Enumerable.Range(0, keyLength));
  664. foreach (var columnMapping in actualColumnMapping) {
  665. valueColumns.Add(columnMapping.column);
  666. columnMap.Add(columnMapping.sourceIndex);
  667. }
  668. result.ValueColumns.AddRange(valueColumns);
  669. result.SelectColumns = columnMap;
  670. result.Name = nameBuilder.BuildIndexName(reflectedType, result);
  671. result.Group = BuildColumnGroup(result);
  672. return result;
  673. }
  674. #endregion
  675. #region Helper methods
  676. private static IEnumerable<TypeInfo> GatherDescendants(TypeInfo type, ICollection<TypeInfo> hierarchyImplementors)
  677. {
  678. foreach (var descendant in type.GetDescendants()) {
  679. if (hierarchyImplementors.Contains(descendant) || descendant.IsAbstract)
  680. continue;
  681. yield return descendant;
  682. foreach (var typeInfo in GatherDescendants(descendant, hierarchyImplementors))
  683. yield return typeInfo;
  684. }
  685. }
  686. private static IEnumerable<ColumnInfo> GatherValueColumns(IEnumerable<ColumnInfo> columns)
  687. {
  688. var nameBuilder = BuildingContext.Demand().NameBuilder;
  689. var valueColumns = new ColumnInfoCollection();
  690. foreach (var column in columns) {
  691. if (valueColumns.Contains(column.Name)) {
  692. if (column.IsSystem)
  693. continue;
  694. var clone = column.Clone();
  695. clone.Name = nameBuilder.BuildColumnName(column);
  696. valueColumns.Add(clone);
  697. }
  698. else
  699. valueColumns.Add(column);
  700. }
  701. return valueColumns;
  702. }
  703. private static ColumnGroup BuildColumnGroup(IndexInfo index)
  704. {
  705. var reflectedType = index.ReflectedType;
  706. var keyColumns = index.IsPrimary
  707. ? Enumerable.Range(0, index.KeyColumns.Count).ToList()
  708. : index.KeyColumns
  709. .Select(pair => pair.Key)
  710. .Concat(index.ValueColumns)
  711. .Select((c, i) => new {c, i})
  712. .Where(arg => arg.c.IsPrimaryKey)
  713. .Select(arg => arg.i)
  714. .ToList();
  715. var columns = Enumerable.Range(0, index.KeyColumns.Count + index.ValueColumns.Count).ToList();
  716. return new ColumnGroup(reflectedType, keyColumns, columns);
  717. }
  718. private static void CleanupTypedIndexes()
  719. {
  720. var context = BuildingContext.Demand();
  721. foreach (var typeInfo in context.Model.Types.Where(t => t.IsEntity)) {
  722. var indexes = typeInfo.Indexes.Where(i => i.IsVirtual).ToList();
  723. var typedIndexes = indexes.Where(i => i.IsTyped);
  724. foreach (var typedIndex in typedIndexes) {
  725. bool remove = false;
  726. foreach (var index in indexes)
  727. if (index.UnderlyingIndexes.Contains(typedIndex)) {
  728. remove = true;
  729. break;
  730. }
  731. if (remove)
  732. typeInfo.Indexes.Remove(typedIndex);
  733. }
  734. }
  735. }
  736. private static void BuildAffectedIndexes()
  737. {
  738. var context = BuildingContext.Demand();
  739. foreach (var typeInfo in context.Model.Types)
  740. if (typeInfo.IsEntity)
  741. BuildAffectedIndexesForEntity(typeInfo);
  742. else if (typeInfo.IsInterface && typeInfo.IsMaterialized)
  743. BuildAffectedIndexesForMaterializedInterface(typeInfo);
  744. }
  745. private static void BuildAffectedIndexesForEntity(TypeInfo typeInfo)
  746. {
  747. var ancestors = new HashSet<TypeInfo>();
  748. ProcessAncestors(typeInfo, ancestor => ancestors.Add(ancestor));
  749. ExtractAffectedIndexes(typeInfo, typeInfo.Indexes, ancestors);
  750. if (typeInfo.Hierarchy.InheritanceSchema==InheritanceSchema.ClassTable)
  751. // Add primary indexes of all ancestors to affected indexes list.
  752. // This is an ugly hack :-(
  753. foreach (var ancestor in ancestors) {
  754. var primaryIndex = ancestor.Indexes
  755. .FindFirst(IndexAttributes.Real | IndexAttributes.Primary);
  756. if (!typeInfo.AffectedIndexes.Contains(primaryIndex))
  757. typeInfo.AffectedIndexes.Add(primaryIndex);
  758. }
  759. }
  760. private static void ExtractAffectedIndexes(
  761. TypeInfo typeInfo, IEnumerable<IndexInfo> sources, ICollection<TypeInfo> ancestors)
  762. {
  763. foreach (var indexInfo in sources) {
  764. if (!indexInfo.IsVirtual) {
  765. bool shouldProcess =
  766. (ancestors.Contains(indexInfo.ReflectedType) || indexInfo.ReflectedType==typeInfo)
  767. && !typeInfo.AffectedIndexes.Contains(indexInfo);
  768. if (shouldProcess) {
  769. typeInfo.AffectedIndexes.Add(indexInfo);
  770. foreach (var pair in indexInfo.KeyColumns) {
  771. if (indexInfo.IsPrimary)
  772. continue;
  773. if (pair.Key.Indexes.Count==0)
  774. pair.Key.Indexes = new NodeCollection<IndexInfo> {indexInfo};
  775. else if (!pair.Key.Indexes.Contains(indexInfo))
  776. pair.Key.Indexes.Add(indexInfo);
  777. }
  778. }
  779. }
  780. ExtractAffectedIndexes(typeInfo, indexInfo.UnderlyingIndexes, ancestors);
  781. }
  782. }
  783. private static void BuildAffectedIndexesForMaterializedInterface(TypeInfo typeInfo)
  784. {
  785. var primaryIndex = typeInfo.Indexes.PrimaryIndex;
  786. foreach (var descendant in typeInfo.GetDescendants(true).Where(t => t.IsEntity).Distinct()) {
  787. descendant.AffectedIndexes.Add(primaryIndex);
  788. foreach (var indexInfo in typeInfo.Indexes.Find(IndexAttributes.Primary, MatchType.None)) {
  789. var descendantIndex = descendant.Indexes.Where(i => i.DeclaringIndex==indexInfo.DeclaringIndex).FirstOrDefault();
  790. if (descendantIndex!=null)
  791. foreach (var pair in descendantIndex.KeyColumns)
  792. if (pair.Key.Indexes.Count==0)
  793. pair.Key.Indexes = new NodeCollection<IndexInfo> {indexInfo};
  794. else
  795. pair.Key.Indexes.Add(indexInfo);
  796. }
  797. }
  798. }
  799. private static void ProcessAncestors(TypeInfo typeInfo, Action<TypeInfo> ancestorProcessor)
  800. {
  801. var context = BuildingContext.Demand();
  802. var root = typeInfo.Hierarchy.Root;
  803. if (root==typeInfo)
  804. return;
  805. var ancestor = context.Model.Types.FindAncestor(typeInfo);
  806. if (ancestor==null)
  807. return;
  808. do {
  809. ancestorProcessor.Invoke(ancestor);
  810. if (ancestor==root)
  811. break;
  812. ancestor = context.Model.Types.FindAncestor(ancestor);
  813. } while (ancestor!=null);
  814. }
  815. #endregion
  816. }
  817. }