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