File: EFDataModelProvider.cs

package info (click to toggle)
mono 6.12.0.199%2Bdfsg-6
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 1,296,836 kB
  • sloc: cs: 11,181,803; xml: 2,850,076; ansic: 699,709; cpp: 123,344; perl: 59,361; javascript: 30,841; asm: 21,853; makefile: 20,405; sh: 15,009; python: 4,839; pascal: 925; sql: 859; sed: 16; php: 1
file content (129 lines) | stat: -rw-r--r-- 5,885 bytes parent folder | download | duplicates (9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.Metadata.Edm;
using System.Data.Objects;
using System.Diagnostics;
using System.Globalization;
using System.Linq;

namespace System.Web.DynamicData.ModelProviders {
    internal sealed class EFDataModelProvider : DataModelProvider {
        private ReadOnlyCollection<TableProvider> _tables;

        internal Dictionary<long, EFColumnProvider> RelationshipEndLookup { get; private set; }
        internal Dictionary<EntityType, EFTableProvider> TableEndLookup { get; private set; }
        private Func<object> ContextFactory { get; set; }
        private Dictionary<EdmType, Type> _entityTypeToClrType = new Dictionary<EdmType, Type>();
        private ObjectContext _context;
        private ObjectItemCollection _objectSpaceItems;

        public EFDataModelProvider(object contextInstance, Func<object> contextFactory) {
            ContextFactory = contextFactory;
            RelationshipEndLookup = new Dictionary<long, EFColumnProvider>();
            TableEndLookup = new Dictionary<EntityType, EFTableProvider>();

            _context = (ObjectContext)contextInstance ?? (ObjectContext)CreateContext();
            ContextType = _context.GetType();

            // get a "container" (a scope at the instance level)
            EntityContainer container = _context.MetadataWorkspace.GetEntityContainer(_context.DefaultContainerName, DataSpace.CSpace);
            // load object space metadata
            _context.MetadataWorkspace.LoadFromAssembly(ContextType.Assembly);
            _objectSpaceItems = (ObjectItemCollection)_context.MetadataWorkspace.GetItemCollection(DataSpace.OSpace);

            var tables = new List<TableProvider>();

            // Create a dictionary from entity type to entity set. The entity type should be at the root of any inheritance chain.
            IDictionary<EntityType, EntitySet> entitySetLookup = container.BaseEntitySets.OfType<EntitySet>().ToDictionary(e => e.ElementType);

            // Create a lookup from parent entity to entity
            ILookup<EntityType, EntityType> derivedTypesLookup = _context.MetadataWorkspace.GetItems<EntityType>(DataSpace.CSpace).ToLookup(e => (EntityType)e.BaseType);

            // Keeps track of the current entity set being processed
            EntitySet currentEntitySet = null;

            // Do a DFS to get the inheritance hierarchy in order
            // i.e. Consider the hierarchy
            // null -> Person
            // Person -> Employee, Contact
            // Employee -> SalesPerson, Programmer
            // We'll walk the children in a depth first order -> Person, Employee, SalesPerson, Programmer, Contact.
            var objectStack = new Stack<EntityType>();
            // Start will null (the root of the hierarchy)
            objectStack.Push(null);
            while (objectStack.Any()) {
                EntityType entityType = objectStack.Pop();
                if (entityType != null) {
                    // Update the entity set when we are at another root type (a type without a base type).
                    if (entityType.BaseType == null) {
                        currentEntitySet = entitySetLookup[entityType];
                    }

                    var table = CreateTableProvider(currentEntitySet, entityType);
                    tables.Add(table);
                }

                foreach (EntityType derivedEntityType in derivedTypesLookup[entityType]) {
                    // Push the derived entity types on the stack
                    objectStack.Push(derivedEntityType);
                }
            }

            _tables = tables.AsReadOnly();
        }

        public override object CreateContext() {
            return ContextFactory();
        }

        public override ReadOnlyCollection<TableProvider> Tables {
            get {
                return _tables;
            }
        }

        internal Type GetClrType(EdmType entityType) {
            var result = _entityTypeToClrType[entityType];
            Debug.Assert(result != null, String.Format(CultureInfo.CurrentCulture, "Cannot map EdmType '{0}' to matching CLR Type", entityType));
            return result;
        }

        internal Type GetClrType(EnumType enumType) {
            var objectSpaceType = (EnumType)_context.MetadataWorkspace.GetObjectSpaceType(enumType);
            return _objectSpaceItems.GetClrType(objectSpaceType);
        }

        private Type GetClrType(EntityType entityType) {
            var objectSpaceType = (EntityType)_context.MetadataWorkspace.GetObjectSpaceType(entityType);
            return _objectSpaceItems.GetClrType(objectSpaceType);
        }

        private TableProvider CreateTableProvider(EntitySet entitySet, EntityType entityType) {
            // Get the parent clr type
            Type parentClrType = null;
            EntityType parentEntityType = entityType.BaseType as EntityType;
            if (parentEntityType != null) {
                parentClrType = GetClrType(parentEntityType);
            }

            Type rootClrType = GetClrType(entitySet.ElementType);
            Type clrType = GetClrType(entityType);

            _entityTypeToClrType[entityType] = clrType;

            // Normally, use the entity set name as the table name
            string tableName = entitySet.Name;

            // But in inheritance scenarios where all types in the hierarchy share the same entity set,
            // we need to use the type name instead for the table name.
            if (parentClrType != null) {
                tableName = entityType.Name;
            }

            EFTableProvider table = new EFTableProvider(this, entitySet, entityType, clrType, parentClrType, rootClrType, tableName);
            TableEndLookup[entityType] = table;

            return table;
        }
    }
}