예제 #1
0
        public static void ValidateForPersistence(this AggregateRootType aggregateRootType)
        {
            if (aggregateRootType.NaturalKey == null)
            {
                throw new RuntimeException(
                          string.Format(
                              CultureInfo.InvariantCulture,
                              @"The aggregate root of type '{0}' does not have a natural key defined.
To fix this issue, either:
- use a bootstrapper to define a natural key, or
- decorate the natural key property on the aggregate root with the [dddlib.NaturalKey] attribute.",
                              aggregateRootType.RuntimeType))
                      {
                          HelpLink = "https://github.com/dddlib/dddlib/wiki/Aggregate-Root-Equality",
                      };
            }

            if (aggregateRootType.UninitializedFactory == null)
            {
                throw new RuntimeException(
                          string.Format(
                              CultureInfo.InvariantCulture,
                              @"The aggregate root of type '{0}' does not have a factory method registered with the runtime.
To fix this issue, either:
- use a bootstrapper to register a factory method with the runtime, or
- add a default constructor to the aggregate root.",
                              aggregateRootType.RuntimeType))
                      {
                          HelpLink = "https://github.com/dddlib/dddlib/wiki/Aggregate-Root-Reconstitution",
                      };
            }
        }
 public override int GetHashCode()
 {
     unchecked
     {
         return((AggregateRootType.GetHashCode() * 397) ^ AggregateRootId.GetHashCode());
     }
 }
        public ICollection <IProjectionEntry> GetEntries(AggregateRootType aggregateRootType)
        {
            Contract.Requires(aggregateRootType != null);
            Contract.Ensures(Contract.Result <ICollection <IProjectionEntry> >() != null);

            throw new NotImplementedException();
        }
예제 #4
0
        public AggregateRootType Create(Type type)
        {
            var entityType = default(EntityType);

            foreach (var subType in type.GetTypeHierarchyUntil(typeof(object)).Reverse())
            {
                if (entityType == null)
                {
                    entityType = new EntityType(subType, this.typeAnalyzerService);
                    continue;
                }

                if (this.typeAnalyzerService.IsValidAggregateRoot(subType))
                {
                    break;
                }

                entityType = new EntityType(subType, this.typeAnalyzerService, entityType);
            }

            var aggregateRootType = default(AggregateRootType);

            foreach (var subType in type.GetTypeHierarchyUntil(typeof(Entity)).Reverse())
            {
                aggregateRootType = new AggregateRootType(subType, this.typeAnalyzerService, aggregateRootType ?? entityType);
            }

            var configuration = new BootstrapperConfiguration(aggregateRootType, this.typeAnalyzerService);
            var bootstrapper  = this.bootstrapperProvider.GetBootstrapper(type);

            bootstrapper.Invoke(configuration);

            return(aggregateRootType);
        }
예제 #5
0
            public TypeInformation(AggregateRootType aggregateRootType)
            {
                Guard.Against.Null(() => aggregateRootType);

                this.EventDispatcher = aggregateRootType.EventDispatcher;
                this.PersistEvents   = aggregateRootType.PersistEvents;
            }
        public ISnapshotPolicy GetPolicy(AggregateRootType eventProviderType)
        {
            Contract.Requires(eventProviderType != null);
            Contract.Ensures(Contract.Result <ISnapshotPolicy>() != null);

            throw new NotImplementedException();
        }
        public ICollection <IProjectionManager> GetManagers(AggregateRootType aggregateRootType)
        {
            Contract.Requires(aggregateRootType != null);
            Contract.Ensures(Contract.Result <IEnumerable <IProjectionManager> >() != null);

            throw new NotImplementedException();
        }
예제 #8
0
        public void ApplicationCanCreateRuntimeTypeForValidType()
        {
            // arrange
            var type = typeof(Aggregate);

            var typeAnalyzerService = A.Fake <ITypeAnalyzerService>(o => o.Strict());

            A.CallTo(() => typeAnalyzerService.IsValidAggregateRoot(type)).Returns(true);
            A.CallTo(() => typeAnalyzerService.IsValidEntity(type)).Returns(true);
            A.CallTo(() => typeAnalyzerService.GetNaturalKey(type)).Returns(null);
            A.CallTo(() => typeAnalyzerService.IsValidAggregateRoot(typeof(AggregateRoot))).Returns(true);
            A.CallTo(() => typeAnalyzerService.IsValidEntity(typeof(AggregateRoot))).Returns(true);
            A.CallTo(() => typeAnalyzerService.GetNaturalKey(typeof(AggregateRoot))).Returns(null);
            A.CallTo(() => typeAnalyzerService.IsValidEntity(typeof(Entity))).Returns(true);
            A.CallTo(() => typeAnalyzerService.GetNaturalKey(typeof(Entity))).Returns(null);
            var entityType    = new EntityType(typeof(Entity), typeAnalyzerService);
            var aggregateType = new AggregateRootType(typeof(AggregateRoot), typeAnalyzerService, entityType);
            var expectedType  = new AggregateRootType(type, typeAnalyzerService, aggregateType);
            var factory       = A.Fake <Func <Type, AggregateRootType> >(o => o.Strict());

            A.CallTo(() => factory.Invoke(type)).Returns(expectedType);

            using (new Application(factory, t => null, t => null))
            {
                // act
                var actualType = Application.Current.GetAggregateRootType(type);

                // assert
                actualType.Should().Be(expectedType);
            }
        }
예제 #9
0
        private void ExecuteDomainEvent(IMessage @event)
        {
            var eventType             = @event.GetType();
            var methodName            = "OnDomainEvent";
            var eventTypeFullName     = @event.GetType();
            var domainEventType       = typeof(IDomainEvent);
            var aggregateTypeFullName = AggregateRootType.FullName;

            if (!domainEventType.IsAssignableFrom(eventType))
            {
                throw new MethodNotFoundException($"The method: {methodName}({eventTypeFullName}) in {aggregateTypeFullName} is wrong, reason: {eventTypeFullName} cannot assign to interface: {domainEventType.FullName}.");
            }

            var method = AggregateRootType
                         .GetMethod(methodName,
                                    BindingFlags.Instance | BindingFlags.Public,
                                    null,
                                    new[] { eventType },
                                    null);

            if (method == null)
            {
                throw new MethodNotFoundException($"No {methodName}({eventTypeFullName}) found in {aggregateTypeFullName}.");
            }

            var instance       = Expression.Constant(this);
            var parameter      = Expression.Parameter(eventType, methodName);
            var call           = Expression.Call(instance, method, parameter);
            var lambda         = Expression.Lambda(call, parameter);
            var methodDelegate = lambda.Compile();

            methodDelegate.DynamicInvoke(@event);
        }
        public AggregateRootConfigurationWrapper(AggregateRootType aggregateRootType, IEntityConfigurationWrapper <T> entityConfigurationWrapper)
        {
            Guard.Against.Null(() => aggregateRootType);
            Guard.Against.Null(() => entityConfigurationWrapper);

            this.aggregateRootType          = aggregateRootType;
            this.entityConfigurationWrapper = entityConfigurationWrapper;
        }
예제 #11
0
 public static void ThrowNotFound(this AggregateRootType aggregateRootType, object naturalKey)
 {
     throw new AggregateRootNotFoundException(
               string.Format(
                   CultureInfo.InvariantCulture,
                   "Cannot find the aggregate root of type '{0}' with natural key '{1}'.",
                   aggregateRootType.RuntimeType,
                   naturalKey));
 }
예제 #12
0
        public BootstrapperConfiguration(AggregateRootType aggregateRootType, ITypeAnalyzerService typeAnalyzerService)
        {
            Guard.Against.Null(() => aggregateRootType);
            Guard.Against.Null(() => typeAnalyzerService);

            this.aggregateRootType   = aggregateRootType;
            this.entityType          = aggregateRootType;
            this.typeAnalyzerService = typeAnalyzerService;
        }
        public ProjectionEntry(AggregateRootType aggregateRootType, ProjectionType projectionType, IProjectionManager projectionManager)
            : this(aggregateRootType, projectionType, projectionManager.GetType())
        {
            Contract.Requires(aggregateRootType != null);
            Contract.Requires(projectionType != null);
            Contract.Requires(projectionManager != null);

            ProjectionManager = projectionManager;
        }
예제 #14
0
        private void ExecutingDomainCommand(AggregateRootMessagingContext context, IDomainCommand command)
        {
            var methodName            = "OnDomainCommand";
            var commandType           = command.GetType();
            var commandTypeFullName   = command.GetType();
            var domainCommandType     = typeof(IDomainCommand);
            var aggregateTypeFullName = AggregateRootType.FullName;

            if (!domainCommandType.IsAssignableFrom(commandType))
            {
                throw new MethodNotFoundException($"The method: {methodName}({commandTypeFullName}) in {aggregateTypeFullName} is wrong, reason: {commandTypeFullName} cannot assign to interface: {domainCommandType.FullName}.");
            }

            var methodWithoutContext = AggregateRootType
                                       .GetMethod(methodName,
                                                  BindingFlags.Instance | BindingFlags.Public,
                                                  null,
                                                  new[] { commandType },
                                                  null);

            if (methodWithoutContext != null)
            {
                var instance       = Expression.Constant(this);
                var parameter      = Expression.Parameter(commandType, methodName);
                var call           = Expression.Call(instance, methodWithoutContext, parameter);
                var lambda         = Expression.Lambda(call, parameter);
                var methodDelegate = lambda.Compile();

                methodDelegate.DynamicInvoke(command);

                return;
            }

            var contextType       = context.GetType();
            var methodWithContext = AggregateRootType
                                    .GetMethod(methodName,
                                               BindingFlags.Instance | BindingFlags.Public,
                                               null,
                                               new[] { contextType, commandType },
                                               null);

            if (methodWithContext != null)
            {
                var instance       = Expression.Constant(this);
                var parameter1     = Expression.Parameter(contextType, $"{methodName}_0");
                var parameter2     = Expression.Parameter(commandType, $"{methodName}_1");
                var call           = Expression.Call(instance, methodWithContext, parameter1, parameter2);
                var lambda         = Expression.Lambda(call, parameter1, parameter2);
                var methodDelegate = lambda.Compile();

                methodDelegate.DynamicInvoke(context, command);

                return;
            }

            throw new MethodNotFoundException($"No {methodName}({commandTypeFullName}) found in {aggregateTypeFullName}.");
        }
        public ProjectionEntry(AggregateRootType aggregateRootType, ProjectionType projectionType, Type projectionManagerType)
        {
            Contract.Requires(aggregateRootType != null);
            Contract.Requires(projectionType != null);
            Contract.Requires(projectionManagerType != null);

            AggregateRootType     = aggregateRootType;
            ProjectionType        = projectionType;
            ProjectionManagerType = projectionManagerType;
        }
예제 #16
0
        public ISnapshotProvider GetProvider(AggregateRootType eventProviderType)
        {
            ISnapshotProvider provider;

            if (_providers.TryGetValue(eventProviderType, out provider))
            {
                return(provider);
            }

            return(null);
        }
예제 #17
0
        private SqlCommand CreateSqlCommand(AggregateRootType aggregateRootType, AggregateRootIdentity identity)
        {
            var sqlCommand = new SqlCommand("[dbo].[GetDomainEvents]");

            sqlCommand.CommandType = CommandType.StoredProcedure;

            // set parameters
            sqlCommand.Parameters.Add("@aggregateRootId", SqlDbType.UniqueIdentifier).Value = identity.Value;
            sqlCommand.Parameters.Add("@aggregateRootTypeId", SqlDbType.Binary, 16).Value   = _typeFactory.GetHash(aggregateRootType.Type);

            return(sqlCommand);
        }
예제 #18
0
        private SqlCommand CreateSqlCommand(AggregateRootType aggregateRootType, int skip, int take)
        {
            var sqlCommand = new SqlCommand("[dbo].[GetTransactionsByAggregateRootType]");

            sqlCommand.CommandType = CommandType.StoredProcedure;

            // set parameters
            sqlCommand.Parameters.Add("@aggregateRootTypeId", SqlDbType.Binary, 16).Value = _typeFactory.GetHash(aggregateRootType.Type);
            sqlCommand.Parameters.Add("@skip", SqlDbType.Int).Value = skip;
            sqlCommand.Parameters.Add("@take", SqlDbType.Int).Value = take;

            return(sqlCommand);
        }
예제 #19
0
 public static void Validate(this AggregateRootType aggregateRootType, object naturalKey)
 {
     if (aggregateRootType.NaturalKey.PropertyType != naturalKey.GetType())
     {
         throw new ArgumentException(
                   string.Format(
                       CultureInfo.InvariantCulture,
                       "Invalid natural key value type for aggregate root of type '{0}'. Expected value type of '{1}' but value is type of '{2}'.",
                       aggregateRootType.RuntimeType,
                       aggregateRootType.NaturalKey.PropertyType,
                       naturalKey.GetType()),
                   Guard.Expression.Parse(() => naturalKey));
     }
 }
예제 #20
0
        public static object GetNaturalKey(this AggregateRootType aggregateRootType, AggregateRoot aggregateRoot)
        {
            var naturalKey = aggregateRootType.NaturalKey.GetValue(aggregateRoot);

            if (naturalKey == null)
            {
                // NOTE (Cameron): This mimics the Guard clause functionality by design.
                throw new ArgumentException(
                          "Value cannot be null.",
                          string.Concat(Guard.Expression.Parse(() => aggregateRoot), ".", aggregateRootType.NaturalKey.PropertyName));
            }

            return(naturalKey);
        }
        protected override async Task <EventStream> GetEventStreamAsync(AggregateRootType eventProviderType, AggregateRootIdentity identity)
        {
            // establish command
            var command = new GetDomainEventsCommand(_serializer, _typeFactory, eventProviderType, identity);

            // create connection
            using (var conn = new SqlConnection(_connectionString))
            {
                // connection needs to be open before executing
                await conn.OpenAsync();

                // execute
                return(await command.ExecuteAsync(conn));
            }
        }
예제 #22
0
        public GetDomainEventsCommand(SqlSerializer serializer,
                                      ITypeFactory typeFactory,
                                      AggregateRootType aggregateRootType,
                                      AggregateRootIdentity aggregateRootIdentity)
        {
            Contract.Requires(serializer != null);
            Contract.Requires(aggregateRootType != null);
            Contract.Requires(typeFactory != null);
            Contract.Requires(aggregateRootIdentity != null);

            _serializer            = serializer;
            _typeFactory           = typeFactory;
            _aggregateRootType     = aggregateRootType;
            _aggregateRootIdentity = aggregateRootIdentity;

            _command = CreateSqlCommand(aggregateRootType, aggregateRootIdentity);
        }
예제 #23
0
        public GetTransactionsByAggregateRootTypeCommand(SqlSerializer serializer,
                                                         ITypeFactory typeFactory,
                                                         AggregateRootType aggregateRootType,
                                                         int skip,
                                                         int take)
        {
            Contract.Requires(serializer != null);
            Contract.Requires(aggregateRootType != null);
            Contract.Requires(typeFactory != null);

            _serializer        = serializer;
            _typeFactory       = typeFactory;
            _aggregateRootType = aggregateRootType;

            _sqlDomainEvents = new Collection <SqlDomainEvent>();
            _revisions       = new Collection <SqlRevision>();

            _command = CreateSqlCommand(aggregateRootType, skip, take);
        }
예제 #24
0
        public ICollection <IProjectionManager> GetManagers(AggregateRootType aggregateRootType)
        {
            var managers = new Collection <IProjectionManager>();

            // loop through all entries in catalog to retrieve projection managers
            foreach (var entry in Catalog.GetEntries(aggregateRootType))
            {
                Contract.Assume(entry != null);

                var manager = GetManager(entry);

                if (manager == null)
                {
                    continue;
                }

                managers.Add(manager);
            }

            // return managers
            return(managers);
        }
예제 #25
0
        public void AddProvider(AggregateRootType eventProviderType, ISnapshotProvider snapshotProvider)
        {
            _providers.Add(eventProviderType, snapshotProvider);

            Contract.Assume(GetProvider(eventProviderType) == snapshotProvider);
        }
예제 #26
0
 /// <summary>
 /// Initializes a new instance of the <see cref="AggregateRoot"/> class.
 /// </summary>
 /// <param name="aggregateRootType">The aggregate root type.</param>
 protected AggregateRoot(AggregateRootType aggregateRootType)
     : this(@this => new TypeInformation(aggregateRootType))
 {
 }
 public override int GetHashCode()
 {
     return(AggregateRootType.GetHashCode() + EventType.GetHashCode());
 }
예제 #28
0
        public ISnapshotProvider GetProvider(AggregateRootType eventProviderType)
        {
            Contract.Requires(eventProviderType != null);

            throw new NotImplementedException();
        }
예제 #29
0
 public void AddProvider(AggregateRootType eventProviderType, ISnapshotProvider snapshotProvider)
 {
     Contract.Requires(eventProviderType != null);
     Contract.Requires(snapshotProvider != null);
     Contract.Ensures(GetProvider(eventProviderType) != null);
 }
 public ICollection <IProjectionEntry> GetEntries(AggregateRootType aggregateRootType)
 {
     return(_entries.Where(x => x.AggregateRootType == aggregateRootType).ToList());
 }