public async Task<IEdmModel> GetModelAsync(ModelContext context, CancellationToken cancellationToken) { EdmModel model = null; if (this.InnerHandler != null) { model = await this.InnerHandler.GetModelAsync(context, cancellationToken) as EdmModel; } if (model == null) { // We don't plan to extend an empty model with operations. return null; } this.ScanForOperations(); string existingNamespace = null; if (model.DeclaredNamespaces != null) { existingNamespace = model.DeclaredNamespaces.FirstOrDefault(); } this.BuildOperations(model, existingNamespace); return model; }
/// <summary> /// Asynchronously executes the model flow. /// </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 a domain model. /// </returns> public async Task<IEdmModel> GetModelAsync( ModelContext context, CancellationToken cancellationToken) { Ensure.NotNull(context, "context"); // STEP 1: produce model var producer = context.GetHookPoint<IModelProducer>(); if (producer != null) { context.Model = await producer.ProduceModelAsync( context, cancellationToken); } if (context.Model == null) { context.Model = new EdmModel(); } // STEP 2: extend model var extenders = context.GetHookPoints<IModelExtender>(); foreach (var extender in extenders) { await extender.ExtendModelAsync(context, cancellationToken); } return context.Model; }
private void ExtendModel(ModelContext context) { var method = this.targetType.GetQualifiedMethod("OnModelExtending"); var returnType = typeof(EdmModel); if (method == null || method.ReturnType != returnType) { return; } object target = null; if (!method.IsStatic) { target = context.DomainContext.GetProperty(targetType.AssemblyQualifiedName); if (target == null || !targetType.IsInstanceOfType(target)) { return; } } var parameters = method.GetParameters(); if (parameters.Length != 1 || parameters[0].ParameterType != returnType) { return; } var model = context.Model; var result = (EdmModel)method.Invoke(target, new object[] { model }); if (result != null && result != model) { context.Model = result; } }
public void ExtendModelAsync_UpdatesModel_IfHasOnModelCreatingMethod(Type type) { // Arrange var domain = Activator.CreateInstance(type); var extender = new ConventionalModelExtender(type); var domainConfig = new DomainConfiguration(); domainConfig.EnsureCommitted(); var domainContext = new DomainContext(domainConfig); domainContext.SetProperty(type.AssemblyQualifiedName, domain); var model = GetModel(); var context = new ModelContext(domainContext) { Model = model }; // Act extender.ExtendModelAsync(context, new CancellationToken()); // Assert Assert.Same(model, context.Model); var operations = model.SchemaElements.OfType<IEdmOperation>(); Assert.Single(operations); var operation = operations.Single(); Assert.True(operation.IsBound); Assert.True(operation.IsFunction()); Assert.Equal("MostExpensive", operation.Name); Assert.Equal("ns", operation.Namespace); }
/// <inheritdoc/> public Task ExtendModelAsync( ModelContext context, CancellationToken cancellationToken) { Ensure.NotNull(context); var model = context.Model; foreach (var entitySetProperty in this.AddedEntitySets) { var container = model.EntityContainer as EdmEntityContainer; var elementType = entitySetProperty .PropertyType.GetGenericArguments()[0]; var entityType = context.Model.SchemaElements .OfType<IEdmEntityType>() .SingleOrDefault(se => se.Name == elementType.Name); if (entityType == null) { // TODO GitHubIssue#33 : Add new entity type representing entity shape continue; } container.AddEntitySet(entitySetProperty.Name, entityType); } return Task.FromResult<object>(null); }
public Task ExtendModelAsync( ModelContext context, CancellationToken cancellationToken) { var model = context.Model; var entityContainer = model.EntityContainer as EdmEntityContainer; foreach (ActionMethodInfo actionInfo in this.ActionInfos) { var returnTypeReference = ConventionalActionProvider.GetReturnTypeReference(actionInfo.Method.ReturnType); var action = new EdmAction(entityContainer.Namespace, actionInfo.ActionName, returnTypeReference); foreach (ParameterInfo parameter in actionInfo.Method.GetParameters()) { EdmOperationParameter actionParam = new EdmOperationParameter( action, parameter.Name, ConventionalActionProvider.GetTypeReference(parameter.ParameterType)); action.AddParameter(actionParam); } model.AddElement(action); if (!action.IsBound) { EdmActionImport actionImport = new EdmActionImport(entityContainer, action.Name, action); entityContainer.AddElement(actionImport); } } return Task.FromResult<object>(null); }
public Task<IEdmModel> GetModelAsync(ModelContext context, CancellationToken cancellationToken) { var model = new EdmModel(); var dummyType = new EdmEntityType("NS", "Dummy"); model.AddElement(dummyType); var container = new EdmEntityContainer("NS", "DefaultContainer"); container.AddEntitySet("Test", dummyType); model.AddElement(container); return Task.FromResult((IEdmModel) model); }
public async Task ExtendModelAsync( ModelContext context, CancellationToken cancellationToken) { var entityType = new EdmEntityType( "TestNamespace", "TestName" + _index); context.Model.AddElement(entityType); (context.Model.EntityContainer as EdmEntityContainer) .AddEntitySet("TestEntitySet" + _index, entityType); await Task.Yield(); }
public Task<EdmModel> ProduceModelAsync( ModelContext context, CancellationToken cancellationToken) { var model = new EdmModel(); var entityType = new EdmEntityType( "TestNamespace", "TestName"); var entityContainer = new EdmEntityContainer( "TestNamespace", "Entities"); entityContainer.AddEntitySet("TestEntitySet", entityType); model.AddElement(entityType); model.AddElement(entityContainer); return Task.FromResult(model); }
/// <summary> /// This class will not real build a model, but only get entity set name and entity map from data source /// Then pass the information to publisher layer to build the model. /// </summary> /// <param name="context"> /// The context for processing /// </param> /// <param name="cancellationToken"> /// An optional cancellation token. /// </param> /// <returns> /// Always a null model. /// </returns> public Task<IEdmModel> GetModelAsync(ModelContext context, CancellationToken cancellationToken) { Ensure.NotNull(context, "context"); #if EF7 var dbContext = context.ApiContext.GetApiService<DbContext>(); context.ResourceSetTypeMap = dbContext.GetType().GetProperties() .Where(e => e.PropertyType.FindGenericType(typeof(DbSet<>)) != null) .ToDictionary(e => e.Name, e => e.PropertyType.GetGenericArguments()[0]); context.ResourceTypeKeyPropertiesMap = dbContext.Model.GetEntityTypes().ToDictionary( e => e.ClrType, e => ((ICollection<PropertyInfo>) e.FindPrimaryKey().Properties.Select(p => e.ClrType.GetProperty(p.Name)).ToList())); #else var resourceSetTypeMap = new Dictionary<string, Type>(); var resourceTypeKeyPropertiesMap = new Dictionary<Type, ICollection<PropertyInfo>>(); var dbContext = context.ServiceProvider.GetService<DbContext>(); var efModel = (dbContext as IObjectContextAdapter).ObjectContext.MetadataWorkspace; var efEntityContainer = efModel.GetItems<EntityContainer>(DataSpace.CSpace).Single(); var itemCollection = (ObjectItemCollection)efModel.GetItemCollection(DataSpace.OSpace); foreach (var efEntitySet in efEntityContainer.EntitySets) { var efEntityType = efEntitySet.ElementType; var objectSpaceType = efModel.GetObjectSpaceType(efEntityType); Type clrType = itemCollection.GetClrType(objectSpaceType); // As entity set name and type map resourceSetTypeMap.Add(efEntitySet.Name, clrType); ICollection<PropertyInfo> keyProperties = new List<PropertyInfo>(); foreach (var property in efEntityType.KeyProperties) { keyProperties.Add(clrType.GetProperty(property.Name)); } resourceTypeKeyPropertiesMap.Add(clrType, keyProperties); } context.ResourceSetTypeMap = resourceSetTypeMap; context.ResourceTypeKeyPropertiesMap = resourceTypeKeyPropertiesMap; #endif if (InnerModelBuilder != null) { return InnerModelBuilder.GetModelAsync(context, cancellationToken); } return Task.FromResult<IEdmModel>(null); }
public void ExtendModelAsync_DoesntUpdatesModel_IfWithoutOnModelCreatingMethod() { // Arrange var domain = new AnyDomain(); var type = domain.GetType(); var extender = new ConventionalModelExtender(type); var domainConfig = new DomainConfiguration(); domainConfig.EnsureCommitted(); var domainContext = new DomainContext(domainConfig); domainContext.SetProperty(type.AssemblyQualifiedName, domain); var model = GetModel(); var context = new ModelContext(domainContext) { Model = model }; // Act extender.ExtendModelAsync(context, new CancellationToken()); // Assert Assert.Same(model, context.Model); Assert.Empty(model.SchemaElements.OfType<IEdmOperation>()); }
public Task<IEdmModel> GetModelAsync(ModelContext context, CancellationToken cancellationToken) { var modelBuilder = new ODataConventionModelBuilder(); modelBuilder.Namespace = "Microsoft.OData.Service.Sample.TrippinInMemory.Models"; modelBuilder.EntitySet<Person>("People"); modelBuilder.EntitySet<Airline>("Airlines"); modelBuilder.EntitySet<Airport>("Airports"); return Task.FromResult(modelBuilder.GetEdmModel()); }
/// <inheritdoc/> public async Task<IEdmModel> GetModelAsync(ModelContext context, CancellationToken cancellationToken) { // This means user build a model with customized model builder registered as inner most // Its element will be added to built model. IEdmModel innerModel = null; if (InnerModelBuilder != null) { innerModel = await InnerModelBuilder.GetModelAsync(context, cancellationToken); } var entitySetTypeMap = context.ResourceSetTypeMap; if (entitySetTypeMap == null || entitySetTypeMap.Count == 0) { return innerModel; } // Collection of entity type and set name is set by EF now, // and EF model producer will not build model any more // Web Api OData conversion model built is been used here, // refer to Web Api OData document for the detail conversions been used for model built. var builder = new ODataConventionModelBuilder(); // This namespace is used by container builder.Namespace = entitySetTypeMap.First().Value.Namespace; MethodInfo method = typeof(ODataConventionModelBuilder) .GetMethod("EntitySet", BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy); foreach (var pair in entitySetTypeMap) { // Build a method with the specific type argument var specifiedMethod = method.MakeGenericMethod(pair.Value); var parameters = new object[] { pair.Key }; specifiedMethod.Invoke(builder, parameters); } entitySetTypeMap.Clear(); var entityTypeKeyPropertiesMap = context.ResourceTypeKeyPropertiesMap; if (entityTypeKeyPropertiesMap != null) { foreach (var pair in entityTypeKeyPropertiesMap) { var edmTypeConfiguration = builder.GetTypeConfigurationOrNull(pair.Key) as EntityTypeConfiguration; if (edmTypeConfiguration == null) { continue; } foreach (var property in pair.Value) { edmTypeConfiguration.HasKey(property); } } entityTypeKeyPropertiesMap.Clear(); } var model = (EdmModel)builder.GetEdmModel(); // Add all Inner model content into existing model // When WebApi OData make conversion model builder accept an existing model, this can be removed. if (innerModel != null) { foreach (var element in innerModel.SchemaElements) { if (!(element is EdmEntityContainer)) { model.AddElement(element); } } foreach (var annotation in innerModel.VocabularyAnnotations) { model.AddVocabularyAnnotation(annotation); } var entityContainer = (EdmEntityContainer)model.EntityContainer; var innerEntityContainer = (EdmEntityContainer)innerModel.EntityContainer; if (innerEntityContainer != null) { foreach (var entityset in innerEntityContainer.EntitySets()) { if (entityContainer.FindEntitySet(entityset.Name) == null) { entityContainer.AddEntitySet(entityset.Name, entityset.EntityType()); } } foreach (var singleton in innerEntityContainer.Singletons()) { if (entityContainer.FindEntitySet(singleton.Name) == null) { entityContainer.AddSingleton(singleton.Name, singleton.EntityType()); } } foreach (var operation in innerEntityContainer.OperationImports()) { if (entityContainer.FindOperationImports(operation.Name) == null) { if (operation.IsFunctionImport()) { entityContainer.AddFunctionImport( operation.Name, (EdmFunction)operation.Operation, operation.EntitySet); } else { entityContainer.AddActionImport( operation.Name, (EdmAction)operation.Operation, operation.EntitySet); } } } } } return model; }
public async Task<IEdmModel> GetModelAsync(ModelContext context, CancellationToken cancellationToken) { await Task.Delay(30); Interlocked.Increment(ref CalledCount); return new EdmModel(); }
/// <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<EdmModel> ProduceModelAsync( ModelContext context, CancellationToken cancellationToken) { var model = new EdmModel(); var domainContext = context.DomainContext; var dbContext = domainContext.GetProperty<DbContext>("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(model); }
/// <summary> /// Asynchronously extends the model. /// </summary> /// <param name="context">The context that contains the model.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>The task object that represents this asynchronous operation.</returns> public Task ExtendModelAsync(ModelContext context, CancellationToken cancellationToken) { ExtendModel(context); return Task.WhenAll(); }
public Task<IEdmModel> GetModelAsync(ModelContext context, CancellationToken cancellationToken) { return Task.FromResult<IEdmModel>(model); }
public async Task<IEdmModel> GetModelAsync(ModelContext context, CancellationToken cancellationToken) { IEdmModel innerModel = null; if (this.InnerHandler != null) { innerModel = await this.InnerHandler.GetModelAsync(context, cancellationToken); } var entityType = new EdmEntityType( "TestNamespace", "TestName" + _index); var model = innerModel as EdmModel; Assert.NotNull(model); model.AddElement(entityType); (model.EntityContainer as EdmEntityContainer) .AddEntitySet("TestEntitySet" + _index, entityType); return model; }
/// <inheritdoc/> public async Task<IEdmModel> GetModelAsync(ModelContext context, CancellationToken cancellationToken) { Ensure.NotNull(context, "context"); IEdmModel modelReturned = await GetModelReturnedByInnerHandlerAsync(context, cancellationToken); if (modelReturned == null) { // There is no model returned so return an empty model. var emptyModel = new EdmModel(); emptyModel.EnsureEntityContainer(ModelCache.targetType); return emptyModel; } EdmModel edmModel = modelReturned as EdmModel; if (edmModel == null) { // The model returned is not an EDM model. return modelReturned; } ModelCache.ScanForDeclaredPublicProperties(); ModelCache.BuildEntitySetsAndSingletons(edmModel); ModelCache.AddNavigationPropertyBindings(edmModel); return edmModel; }
public async Task<IEdmModel> GetModelAsync(ModelContext context, CancellationToken cancellationToken) { if (CalledCount++ == 0) { await Task.Delay(100); throw new Exception("Deliberate failure"); } return new EdmModel(); }
private async Task<IEdmModel> GetModelReturnedByInnerHandlerAsync( ModelContext context, CancellationToken cancellationToken) { var innerHandler = InnerModelBuilder; if (innerHandler != null) { return await innerHandler.GetModelAsync(context, cancellationToken); } return null; }
/// <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<EdmModel> ProduceModelAsync( ModelContext context, CancellationToken cancellationToken) { Ensure.NotNull(context); var model = new EdmModel(); var domainContext = context.DomainContext; var dbContext = domainContext.GetProperty<DbContext>("DbContext"); var elementMap = new Dictionary<MetadataItem, IEdmElement>(); var efModel = (dbContext as IObjectContextAdapter) .ObjectContext.MetadataWorkspace; var namespaceName = efModel.GetItems<EntityType>(DataSpace.CSpace) .Select(t => efModel.GetObjectSpaceType(t).NamespaceName) .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 efEntityContainer = efModel.GetItems<EntityContainer>(DataSpace.CSpace).Single(); var entityContainer = new EdmEntityContainer(namespaceName, efEntityContainer.Name); elementMap.Add(efEntityContainer, entityContainer); // TODO GitHubIssue#36 : support complex and enumeration types foreach (var efEntitySet in efEntityContainer.EntitySets) { var efEntityType = efEntitySet.ElementType; if (elementMap.ContainsKey(efEntityType)) { continue; } List<EdmStructuralProperty> concurrencyProperties; var entityType = CreateEntityType(efModel, efEntityType, model, elementMap, out concurrencyProperties); model.AddElement(entityType); elementMap.Add(efEntityType, entityType); var entitySet = entityContainer.AddEntitySet(efEntitySet.Name, entityType); if (concurrencyProperties != null) { model.SetOptimisticConcurrencyAnnotation(entitySet, concurrencyProperties); } elementMap.Add(efEntitySet, entitySet); } foreach (var efAssociationSet in efEntityContainer.AssociationSets) { AddNavigationProperties(efAssociationSet, elementMap); AddNavigationPropertyBindings(efAssociationSet, elementMap); } // TODO GitHubIssue#36 : support function imports model.AddElement(entityContainer); return Task.FromResult(model); }
public Task<IEdmModel> GetModelAsync(ModelContext context, CancellationToken cancellationToken) { throw new NotImplementedException(); }