private static IEdmEntityType CreateEntityType( IModel efModel, IEntityType efEntityType, EdmModel model, out List <EdmStructuralProperty> concurrencyProperties) { // TODO GitHubIssue#36 : support complex and entity inheritance var entityType = new EdmEntityType( efEntityType.ClrType.Namespace, efEntityType.ClrType.Name); concurrencyProperties = null; foreach (var efProperty in efEntityType.GetProperties()) { var type = ModelProducer.GetPrimitiveTypeReference(efProperty); if (type != null) { string defaultValue = null; RelationalPropertyAnnotations annotations = new RelationalPropertyAnnotations(efProperty, null); if (annotations.DefaultValue != null) { defaultValue = annotations.DefaultValue.ToString(); } var property = entityType.AddStructuralProperty( efProperty.Name, type, defaultValue, EdmConcurrencyMode.None); // alway None:replaced by OptimisticConcurrency annotation // TODO GitHubIssue#57: Complete EF7 to EDM model mapping if (efProperty.StoreGeneratedAlways) { SetComputedAnnotation(model, property); } if (efProperty.IsConcurrencyToken) { concurrencyProperties = concurrencyProperties ?? new List <EdmStructuralProperty>(); concurrencyProperties.Add(property); } } } var key = efEntityType.GetPrimaryKey(); if (key != null) { entityType.AddKeys(key.Properties .Select(p => entityType.FindProperty(p.Name)) .Cast <IEdmStructuralProperty>()); } return(entityType); }
private static void CreateNavigations( EdmEntityContainer entityContainer, IEnumerable <IEntityType> entityTypes, Dictionary <IAnnotatable, IEdmElement> elementMap) { foreach (var efEntityType in entityTypes) { foreach (var navi in efEntityType.GetNavigations()) { ModelProducer.AddNavigationProperties(navi, elementMap); ModelProducer.AddNavigationPropertyBindings(navi, entityContainer, elementMap); } } }
/// <summary> /// Asynchronously produces a base model. /// </summary> /// <param name="context"> /// The model context. /// </param> /// <param name="cancellationToken"> /// A cancellation token. /// </param> /// <returns> /// A task that represents the asynchronous /// operation whose result is the base model. /// </returns> public Task <IEdmModel> GetModelAsync( InvocationContext context, CancellationToken cancellationToken) { Ensure.NotNull(context, "context"); var model = new EdmModel(); var dbContext = context.GetApiService <DbContext>(); var elementMap = new Dictionary <IAnnotatable, IEdmElement>(); var entityTypes = dbContext.Model.GetEntityTypes(); string namespaceName = CalcNamespace(dbContext, entityTypes); var entityContainer = new EdmEntityContainer( namespaceName, "Container"); Dictionary <Type, PropertyInfo> dbSetProperties = GetDbSetPropeties(dbContext); // TODO GitHubIssue#36 : support complex and entity inheritance foreach (var efEntityType in entityTypes) { if (elementMap.ContainsKey(efEntityType)) { continue; } List <EdmStructuralProperty> concurrencyProperties; var entityType = ModelProducer.CreateEntityType( efEntityType, model, out concurrencyProperties); model.AddElement(entityType); PropertyInfo propInfo; if (dbSetProperties.TryGetValue(efEntityType.ClrType, out propInfo)) { var entitySet = entityContainer.AddEntitySet(propInfo.Name, entityType); if (concurrencyProperties != null) { model.SetOptimisticConcurrencyAnnotation(entitySet, concurrencyProperties); } } elementMap.Add(efEntityType, entityType); } CreateNavigations(entityContainer, entityTypes, elementMap); // TODO GitHubIssue#36 : support function imports model.AddElement(entityContainer); return(Task.FromResult <IEdmModel>(model)); }
static ModelProducer() { Instance = new ModelProducer(); }
private static void AddNavigationProperties( IModel efModel, INavigation navigation, EdmModel model, IDictionary <IAnnotatable, IEdmElement> elementMap) { if (!navigation.PointsToPrincipal()) { return; } var naviPair = new INavigation[] { navigation, navigation.FindInverse() }; var navPropertyInfos = new EdmNavigationPropertyInfo[2]; for (var i = 0; i < 2; i++) { var navi = naviPair[i]; if (navi == null) { continue; } var efEntityType = navi.DeclaringEntityType; if (!elementMap.ContainsKey(efEntityType)) { continue; } var entityType = elementMap[efEntityType] as IEdmEntityType; var efTargetEntityType = navi.GetTargetType(); if (!elementMap.ContainsKey(efTargetEntityType)) { continue; } var targetEntityType = elementMap[efTargetEntityType] as IEdmEntityType; navPropertyInfos[i] = new EdmNavigationPropertyInfo() { ContainsTarget = false, Name = navi.Name, Target = targetEntityType, TargetMultiplicity = ModelProducer.GetEdmMultiplicity(navi), }; var foreignKey = navi.ForeignKey; if (foreignKey != null && navi.PointsToPrincipal()) { navPropertyInfos[i].OnDelete = foreignKey.DeleteBehavior == DeleteBehavior.Cascade ? EdmOnDeleteAction.Cascade : EdmOnDeleteAction.None; navPropertyInfos[i].DependentProperties = foreignKey.Properties .Select(p => entityType.FindProperty(p.Name) as IEdmStructuralProperty); navPropertyInfos[i].PrincipalProperties = foreignKey.PrincipalKey.Properties .Select(p => targetEntityType.FindProperty(p.Name) as IEdmStructuralProperty); } } if (navPropertyInfos[0] == null && navPropertyInfos[1] != null) { var efEntityType = navigation.GetTargetType(); var entityType = elementMap[efEntityType] as EdmEntityType; if (entityType.FindProperty(navPropertyInfos[1].Name) == null) { entityType.AddUnidirectionalNavigation(navPropertyInfos[1]); } } if (navPropertyInfos[0] != null && navPropertyInfos[1] == null) { var efEntityType = navigation.DeclaringEntityType; var entityType = elementMap[efEntityType] as EdmEntityType; if (entityType.FindProperty(navPropertyInfos[0].Name) == null) { entityType.AddUnidirectionalNavigation(navPropertyInfos[0]); } } if (navPropertyInfos[0] != null && navPropertyInfos[1] != null) { var efEntityType = navigation.DeclaringEntityType; var entityType = elementMap[efEntityType] as EdmEntityType; if (entityType.FindProperty(navPropertyInfos[0].Name) == null) { entityType.AddBidirectionalNavigation( navPropertyInfos[0], navPropertyInfos[1]); } } }
/// <summary> /// Asynchronously produces a base model. /// </summary> /// <param name="context"> /// The model context. /// </param> /// <param name="cancellationToken"> /// A cancellation token. /// </param> /// <returns> /// A task that represents the asynchronous /// operation whose result is the base model. /// </returns> public Task <IEdmModel> GetModelAsync( InvocationContext context, CancellationToken cancellationToken) { var model = new EdmModel(); var domainContext = context.ApiContext; var dbContext = domainContext.GetApiService <DbContext>(); var elementMap = new Dictionary <IAnnotatable, IEdmElement>(); var efModel = dbContext.Model; var namespaceName = efModel.EntityTypes .Select(t => t.HasClrType() ? t.ClrType.Namespace : null) .Where(t => t != null) .GroupBy(nameSpace => nameSpace) .Select(group => new { NameSpace = group.Key, Count = group.Count(), }) .OrderByDescending(nsItem => nsItem.Count) .Select(nsItem => nsItem.NameSpace) .FirstOrDefault(); if (namespaceName == null) { // When dbContext has not a namespace, just use its type name as namespace. namespaceName = dbContext.GetType().Namespace ?? dbContext.GetType().Name; } var entityTypes = efModel.EntityTypes; var entityContainer = new EdmEntityContainer( namespaceName, "Container"); var dbSetProperties = dbContext.GetType() .GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance) .Where(e => e.PropertyType.IsGenericType && e.PropertyType.GetGenericTypeDefinition() == typeof(DbSet <>)) .ToDictionary(e => e.PropertyType.GetGenericArguments()[0]); // TODO GitHubIssue#36 : support complex and entity inheritance foreach (var efEntityType in entityTypes) { if (elementMap.ContainsKey(efEntityType)) { continue; } List <EdmStructuralProperty> concurrencyProperties; var entityType = ModelProducer.CreateEntityType( efModel, efEntityType, model, out concurrencyProperties); model.AddElement(entityType); elementMap.Add(efEntityType, entityType); System.Reflection.PropertyInfo propInfo; if (dbSetProperties.TryGetValue(efEntityType.ClrType, out propInfo)) { var entitySet = entityContainer.AddEntitySet(propInfo.Name, entityType); if (concurrencyProperties != null) { model.SetOptimisticConcurrencyAnnotation(entitySet, concurrencyProperties); } } } foreach (var efEntityType in entityTypes) { foreach (var navi in efEntityType.GetNavigations()) { ModelProducer.AddNavigationProperties( efModel, navi, model, elementMap); ModelProducer.AddNavigationPropertyBindings( efModel, navi, entityContainer, elementMap); } } // TODO GitHubIssue#36 : support function imports model.AddElement(entityContainer); return(Task.FromResult <IEdmModel>(model)); }