Developed mongodb model building system.

pull/272/head
Halil İbrahim Kalkan 8 years ago
parent 91725a7b90
commit abf84ec2ce

@ -10,6 +10,7 @@ namespace Volo.Abp.EntityFrameworkCore.DependencyInjection
public EfCoreRepositoryRegistrar(AbpDbContextRegistrationOptions options)
: base(options)
{
}
protected override IEnumerable<Type> GetEntityTypes(Type dbContextType)

@ -9,8 +9,6 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
IMongoDatabase Database { get; }
IMongoCollection<TEntity> Collection { get; }
string CollectionName { get; }
}
public interface IMongoDbRepository<TEntity, TKey> : IMongoDbRepository<TEntity>, IRepository<TEntity, TKey>

@ -15,8 +15,6 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
where TMongoDbContext : IAbpMongoDbContext
where TEntity : class, IEntity
{
public virtual string CollectionName => DbContext.GetCollectionName<TEntity>();
public virtual IMongoCollection<TEntity> Collection => DbContext.Collection<TEntity>();
public virtual IMongoDatabase Database => DbContext.Database;

@ -19,12 +19,6 @@ namespace Volo.Abp.Domain.Repositories
return repository.ToMongoDbRepository().Collection;
}
public static string GetCollectionName<TEntity, TKey>(this IBasicRepository<TEntity, TKey> repository)
where TEntity : class, IEntity<TKey>
{
return repository.ToMongoDbRepository().CollectionName;
}
public static IMongoDbRepository<TEntity, TKey> ToMongoDbRepository<TEntity, TKey>(this IBasicRepository<TEntity, TKey> repository)
where TEntity : class, IEntity<TKey>
{

@ -1,31 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using MongoDB.Driver;
namespace Volo.Abp.MongoDB
{
public abstract class AbpMongoDbContext : IAbpMongoDbContext
{
private static readonly MongoEntityMapping[] EmptyTypeList = new MongoEntityMapping[0];
public IMongoModelSource ModelSource { get; set; }
public IMongoDatabase Database { get; private set; }
private readonly Lazy<Dictionary<Type, MongoEntityMapping>> _mappingsByType;
protected AbpMongoDbContext()
protected internal virtual void CreateModel(IMongoModelBuilder modelBuilder)
{
//TODO: Cache model/mappings
_mappingsByType = new Lazy<Dictionary<Type, MongoEntityMapping>>(() =>
{
return GetMappings().ToDictionary(m => m.EntityType);
}, true);
}
public virtual IReadOnlyList<MongoEntityMapping> GetMappings()
public virtual void InitializeDatabase(IMongoDatabase database)
{
return EmptyTypeList;
Database = database;
}
public virtual IMongoCollection<T> Collection<T>()
@ -33,25 +24,21 @@ namespace Volo.Abp.MongoDB
return Database.GetCollection<T>(GetCollectionName<T>());
}
public virtual string GetCollectionName<T>()
protected virtual string GetCollectionName<T>()
{
return GetMapping<T>().CollectionName;
return GetEntityModel<T>().CollectionName;
}
protected virtual MongoEntityMapping GetMapping<T>()
protected virtual IMongoEntityModel GetEntityModel<TEntity>()
{
var mapping = _mappingsByType.Value.GetOrDefault(typeof(T));
if (mapping == null)
var model = ModelSource.GetModel(this).Entities.GetOrDefault(typeof(TEntity));
if (model == null)
{
throw new AbpException("Unmapped entity type: " + typeof(T).AssemblyQualifiedName);
throw new AbpException("Could not find a model for given entity type: " + typeof(TEntity).AssemblyQualifiedName);
}
return mapping;
}
public void InitializeDatabase(IMongoDatabase database)
{
Database = database;
return model;
}
}
}

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Domain.Repositories.MongoDB;
@ -11,13 +10,12 @@ namespace Volo.Abp.MongoDB.DependencyInjection
public MongoDbRepositoryRegistrar(MongoDbContextRegistrationOptions options)
: base(options)
{
}
protected override IEnumerable<Type> GetEntityTypes(Type dbContextType)
{
//TODO: Instead of getting from Options.OriginalDbContextType, we may consider to add entities as properties to the dbcontext, just like EF Core!
var mongoDbContext = (IAbpMongoDbContext)Activator.CreateInstance(Options.OriginalDbContextType);
return mongoDbContext.GetMappings().Select(m => m.EntityType);
return MongoDbContextHelper.GetEntityTypes(dbContextType);
}
protected override Type GetRepositoryType(Type dbContextType, Type entityType)

@ -1,4 +1,3 @@
using System.Collections.Generic;
using MongoDB.Driver;
namespace Volo.Abp.MongoDB
@ -8,9 +7,5 @@ namespace Volo.Abp.MongoDB
IMongoDatabase Database { get; }
IMongoCollection<T> Collection<T>();
string GetCollectionName<T>();
IReadOnlyList<MongoEntityMapping> GetMappings(); //TODO: Consider to remove from the interface
}
}

@ -0,0 +1,11 @@
using System;
namespace Volo.Abp.MongoDB
{
public interface IMongoEntityModel
{
Type EntityType { get; }
string CollectionName { get; }
}
}

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
namespace Volo.Abp.MongoDB
{
public interface IMongoModelBuilder
{
void Entity<TEntity>([NotNull] Action<MongoEntityModelBuilder> buildAction);
void Entity([NotNull] Type entityType, [NotNull] Action<MongoEntityModelBuilder> buildAction);
IReadOnlyList<MongoEntityModelBuilder> GetEntities();
}
}

@ -0,0 +1,7 @@
namespace Volo.Abp.MongoDB
{
public interface IMongoModelSource
{
MongoDbContextModel GetModel(AbpMongoDbContext dbContext);
}
}

@ -0,0 +1,19 @@
using System;
namespace Volo.Abp.MongoDB
{
public class MongoCollectionAttribute : Attribute
{
public string CollectionName { get; set; }
public MongoCollectionAttribute()
{
}
public MongoCollectionAttribute(string collectionName)
{
CollectionName = collectionName;
}
}
}

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using MongoDB.Driver;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Reflection;
namespace Volo.Abp.MongoDB
{
internal static class MongoDbContextHelper
{
public static IEnumerable<Type> GetEntityTypes(Type dbContextType)
{
return
from property in dbContextType.GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.Instance)
where
ReflectionHelper.IsAssignableToGenericType(property.PropertyType, typeof(IMongoCollection<>)) &&
typeof(IEntity).IsAssignableFrom(property.PropertyType.GenericTypeArguments[0])
select property.PropertyType.GenericTypeArguments[0];
}
}
}

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
namespace Volo.Abp.MongoDB
{
public class MongoDbContextModel
{
public IReadOnlyDictionary<Type, IMongoEntityModel> Entities { get; }
public MongoDbContextModel(IReadOnlyDictionary<Type, IMongoEntityModel> entities)
{
Entities = entities;
}
}
}

@ -1,17 +0,0 @@
using System;
namespace Volo.Abp.MongoDB
{
public class MongoEntityMapping
{
public Type EntityType { get; set; }
public string CollectionName { get; set; }
public MongoEntityMapping(Type entityType, string collectionName = null)
{
EntityType = entityType;
CollectionName = collectionName ?? entityType.Name;
}
}
}

@ -0,0 +1,18 @@
using System;
namespace Volo.Abp.MongoDB
{
public class MongoEntityModelBuilder : IMongoEntityModel
{
public Type EntityType { get; }
public string CollectionName { get; set; }
public MongoEntityModelBuilder(Type entityType)
{
Check.NotNull(entityType, nameof(entityType));
EntityType = entityType;
}
}
}

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using JetBrains.Annotations;
namespace Volo.Abp.MongoDB
{
public class MongoModelBuilder : IMongoModelBuilder
{
private readonly Dictionary<Type, MongoEntityModelBuilder> _entityModelBuilders;
public MongoModelBuilder()
{
_entityModelBuilders = new Dictionary<Type, MongoEntityModelBuilder>();
}
public MongoDbContextModel Build()
{
var entityModels = _entityModelBuilders
.Select(x => x.Value)
.ToImmutableDictionary(x => x.EntityType, x => (IMongoEntityModel) x);
return new MongoDbContextModel(entityModels);
}
public virtual void Entity<TEntity>([NotNull] Action<MongoEntityModelBuilder> buildAction)
{
Entity(typeof(TEntity), buildAction);
}
public virtual void Entity([NotNull] Type entityType, [NotNull] Action<MongoEntityModelBuilder> buildAction)
{
Check.NotNull(entityType, nameof(entityType));
Check.NotNull(buildAction, nameof(buildAction));
var model = _entityModelBuilders.GetOrAdd(entityType, () => new MongoEntityModelBuilder(entityType));
buildAction(model);
}
public virtual IReadOnlyList<MongoEntityModelBuilder> GetEntities()
{
return _entityModelBuilders.Values.ToImmutableList();
}
}
}

@ -0,0 +1,26 @@
using JetBrains.Annotations;
namespace Volo.Abp.MongoDB
{
public class MongoModelBuilderConfigurationOptions
{
[NotNull]
public string CollectionPrefix
{
get => _collectionPrefix;
set
{
Check.NotNull(value, nameof(value), $"{nameof(CollectionPrefix)} can not be null! Set to empty string if you don't want a collection prefix.");
_collectionPrefix = value;
}
}
private string _collectionPrefix;
public MongoModelBuilderConfigurationOptions([NotNull] string collectionPrefix = "")
{
Check.NotNull(collectionPrefix, nameof(collectionPrefix));
CollectionPrefix = collectionPrefix;
}
}
}

@ -0,0 +1,68 @@
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Reflection;
using MongoDB.Driver;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Reflection;
namespace Volo.Abp.MongoDB
{
public class MongoModelSource : IMongoModelSource, ISingletonDependency
{
protected readonly ConcurrentDictionary<Type, MongoDbContextModel> ModelCache = new ConcurrentDictionary<Type, MongoDbContextModel>();
public virtual MongoDbContextModel GetModel(AbpMongoDbContext dbContext)
{
return ModelCache.GetOrAdd(
dbContext.GetType(),
_ => CreateModel(dbContext)
);
}
protected virtual MongoDbContextModel CreateModel(AbpMongoDbContext dbContext)
{
var modelBuilder = CreateModelBuilder();
BuildModelFromDbContextType(modelBuilder, dbContext.GetType());
BuildModelFromDbContextInstance(modelBuilder, dbContext);
return modelBuilder.Build();
}
protected virtual MongoModelBuilder CreateModelBuilder()
{
return new MongoModelBuilder();
}
protected virtual void BuildModelFromDbContextType(IMongoModelBuilder modelBuilder, Type dbContextType)
{
var collectionProperties =
from property in dbContextType.GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.Instance)
where
ReflectionHelper.IsAssignableToGenericType(property.PropertyType, typeof(IMongoCollection<>)) &&
typeof(IEntity).IsAssignableFrom(property.PropertyType.GenericTypeArguments[0])
select property;
foreach (var collectionProperty in collectionProperties)
{
BuildModelFromDbContextCollectionProperty(modelBuilder, collectionProperty);
}
}
protected virtual void BuildModelFromDbContextCollectionProperty(IMongoModelBuilder modelBuilder, PropertyInfo collectionProperty)
{
var entityType = collectionProperty.PropertyType.GenericTypeArguments[0];
var collectionAttribute = collectionProperty.GetCustomAttributes().OfType<MongoCollectionAttribute>().FirstOrDefault();
modelBuilder.Entity(entityType, b =>
{
b.CollectionName = collectionAttribute?.CollectionName ?? collectionProperty.Name;
});
}
protected virtual void BuildModelFromDbContextInstance(IMongoModelBuilder modelBuilder, AbpMongoDbContext dbContext)
{
dbContext.CreateModel(modelBuilder);
}
}
}

@ -1,5 +1,4 @@
using System.Collections.Generic;
using MongoDB.Driver;
using MongoDB.Driver;
using Volo.Abp.Data;
using Volo.Abp.MongoDB;
using Volo.Abp.TestApp.Domain;
@ -9,23 +8,19 @@ namespace Volo.Abp.TestApp.MongoDb
[ConnectionStringName("TestApp")]
public class TestAppMongoDbContext : AbpMongoDbContext, ITestAppMongoDbContext
{
//TODO: We can set collections automatically, lik EF Core
//TODO: We can get collection names conventionally, or by an attribute
[MongoCollection("Persons")] //Intentially changed the collection name to test it
public IMongoCollection<Person> People => Collection<Person>();
public IMongoCollection<City> Cities => Collection<City>();
//TODO: Default implementation should read IMongoCollections from the context!
//GetMappings should send a context and we add to it. Rename to ConfigureMappings.
public override IReadOnlyList<MongoEntityMapping> GetMappings()
protected override void CreateModel(IMongoModelBuilder modelBuilder)
{
return new[]
base.CreateModel(modelBuilder);
modelBuilder.Entity<City>(b =>
{
new MongoEntityMapping(typeof(Person), "People"),
new MongoEntityMapping(typeof(City), "Cities")
};
b.CollectionName = "MyCities";
});
}
}
}

Loading…
Cancel
Save