public void Should_Write_History_For_Tracked_Property_Foreign_Key()
        {
            /* Post.BlogId has Audited attribute. */

            var blogId = CreateBlogAndGetId();

            _entityHistoryStore.ClearReceivedCalls();

            Guid post1Id;

            using (var uow = Resolve <IUnitOfWorkManager>().Begin())
            {
                var blog1 = _blogRepository.Single(b => b.Id == 1);
                var blog2 = _blogRepository.Single(b => b.Id == 2);
                var post1 = _postRepository.Single(b => b.Body == "test-post-1-body");
                post1Id = post1.Id;

                // Change foreign key by assigning navigation property
                post1.Blog = blog2;
                _postRepository.Update(post1);

                uow.Complete();
            }

            _entityHistoryStore.Received().SaveAsync(Arg.Is <EntityChangeSet>(
                                                         s => s.EntityChanges.Count == 1 &&
                                                         s.EntityChanges[0].ChangeType == EntityChangeType.Updated &&
                                                         s.EntityChanges[0].EntityId == post1Id.ToJsonString(false, false) &&
                                                         s.EntityChanges[0].EntityTypeFullName == typeof(Post).FullName &&
                                                         s.EntityChanges[0].PropertyChanges.Count == 1 // Post.BlogId
                                                         ));
        }
Exemple #2
0
        public void Should_Write_History_For_Tracked_Property_Foreign_Key()
        {
            /* Post.BlogId has Audited attribute. */

            var blogId = CreateBlogAndGetId();

            _entityHistoryStore.ClearReceivedCalls();

            Guid post1Id;

            using (var uow = Resolve <IUnitOfWorkManager>().Begin())
            {
                var blog1 = _blogRepository.Single(b => b.Id == 1);
                var blog2 = _blogRepository.Single(b => b.Id == 2);
                var post1 = _postRepository.Single(b => b.Body == "test-post-1-body");
                post1Id = post1.Id;

                // Change foreign key by assigning navigation property
                post1.Blog = blog2;
                _postRepository.Update(post1);

                uow.Complete();
            }

            Predicate <EntityChangeSet> predicate = s =>
            {
                s.EntityChanges.Count.ShouldBe(1);

                var entityChange = s.EntityChanges[0];
                entityChange.ChangeType.ShouldBe(EntityChangeType.Updated);
                entityChange.EntityId.ShouldBe(post1Id.ToJsonString(false, false));
                entityChange.EntityTypeFullName.ShouldBe(typeof(Post).FullName);
                entityChange.PropertyChanges.Count.ShouldBe(1);

                var propertyChange = entityChange.PropertyChanges.Single();
                propertyChange.PropertyName.ShouldBe(nameof(Post.BlogId));

                return(true);
            };

            _entityHistoryStore.Received().Save(Arg.Is <EntityChangeSet>(s => predicate(s)));
        }
Exemple #3
0
        public void Should_Write_History_For_TPH_Tracked_Entities_With_One_To_Many_Relationship_Create()
        {
            var studentId = CreateStudentAndGetId();

            Resolve <IEntityHistoryConfiguration>().Selectors
            .Add("Selected", typeof(Student), typeof(StudentLectureNote));

            _entityHistoryStore.ClearReceivedCalls();

            WithUnitOfWork(() =>
            {
                var student     = _studentRepository.Get(studentId);
                var lectureNote = new StudentLectureNote()
                {
                    Student    = student,
                    CourseName = "Course1",
                    Note       = 100
                };
                student.LectureNotes.Add(lectureNote);

                _studentRepository.Update(student);
            });

            Predicate <EntityChangeSet> predicate = s =>
            {
                s.EntityChanges.Count.ShouldBe(1);

                var entityChange = s.EntityChanges.Single(ec => ec.EntityTypeFullName == typeof(StudentLectureNote).FullName);
                ((DateTime?)entityChange.ChangeTime).ShouldNotBe(null);
                entityChange.ChangeType.ShouldBe(EntityChangeType.Created);
                entityChange.PropertyChanges.Count.ShouldBe(3);

                entityChange.PropertyChanges.Single(p => p.PropertyName == nameof(StudentLectureNote.StudentId))
                .NewValue.ShouldBe(studentId.ToString());

                return(true);
            };

            _entityHistoryStore.Received().Save(Arg.Is <EntityChangeSet>(s => predicate(s)));
        }
Exemple #4
0
        public void Should_Not_Write_History_If_Invalid_Entity_Has_Property_With_Audited_Attribute_Updated()
        {
            //Arrange
            UsingDbContext((context) =>
            {
                context.Categories.Add(new Category {
                    DisplayName = "My Category"
                });
                context.SaveChanges();
            });
            _entityHistoryStore.ClearReceivedCalls();

            //Act
            UsingDbContext((context) =>
            {
                var category         = context.Categories.Single(c => c.DisplayName == "My Category");
                category.DisplayName = "Invalid Category";
                context.SaveChanges();
            });

            //Assert
            _entityHistoryStore.DidNotReceive().Save(Arg.Any <EntityChangeSet>());
        }
Exemple #5
0
        public void Should_Write_History_For_Owned_Entities_Of_Audited_Entities_Update()
        {
            // Blog is the owner of BlogPromotion and has Audited attribute.
            // Advertisement is not the owner of BlogPromotion.
            // Therefore, BlogPromotion should follow Blog and have entity history.

            //Arrange
            int advertisement2Id;

            using (var uow = Resolve <IUnitOfWorkManager>().Begin())
            {
                // Owned entities are not available via DbContext -> DbSet,
                var blog2 = _blogRepository.Single(b => b.Name == "test-blog-2");
                blog2.Promotions.Count.ShouldBe(0);

                var advertisement1 = _advertisementRepository.Single(a => a.Banner == "test-advertisement-1");
                blog2.Promotions.Add(new BlogPromotion {
                    AdvertisementId = advertisement1.Id
                });

                uow.Complete();

                blog2.Promotions.Count.ShouldBe(1);
            };
            using (var uow = Resolve <IUnitOfWorkManager>().Begin())
            {
                // Owned entities are not available via DbContext -> DbSet,
                var blog1 = _blogRepository.Single(b => b.Name == "test-blog-1");
                blog1.Promotions.Count.ShouldBe(0);

                var advertisement2 = _advertisementRepository.Single(a => a.Banner == "test-advertisement-2");
                advertisement2Id = advertisement2.Id;

                blog1.Promotions.Add(new BlogPromotion {
                    AdvertisementId = advertisement2.Id, Title = "test-promotion-2"
                });
                uow.Complete();

                blog1.Promotions.Count.ShouldBe(1);
            };
            _entityHistoryStore.ClearReceivedCalls();

            //Act
            using (var uow = Resolve <IUnitOfWorkManager>().Begin())
            {
                var blog1 = _blogRepository.Single(b => b.Name == "test-blog-1");

                var blog1Promotion2 = blog1.Promotions.Single(p => p.AdvertisementId == advertisement2Id);
                blog1Promotion2.Title = "test-promotion-2-updated";
                uow.Complete();
            };

            WithUnitOfWork(() =>
            {
                // Owned entities are not available via DbContext -> DbSet,
                var blog1 = _blogRepository.Single(b => b.Name == "test-blog-1");
                blog1.Promotions.Count.ShouldBe(1);
            });

            //Assert
            Predicate <EntityChangeSet> predicate = s =>
            {
                s.EntityChanges.Count.ShouldBe(1);

                // The primary key (Id) of BlogPromotion is a shadow property and BlogId being the foreign key to its owner, Blog,
                // EF Core is keeping the values of PK of Blog and FK (BlogId) of BlogPromotion the same
                // PK of BlogPromotion is unique across different owners, e.g. Blog1 has BlogPromotion1, BlogPromotion2 and Blog2 has BlogPromotion3
                // See https://docs.microsoft.com/en-us/ef/core/modeling/owned-entities#collections-of-owned-types

                // We assume that are 2 BlogPromotion (with Id 1, 2) being created sequentially for Blog 2 and Blog 1 respectively
                const int blog1Promotion2Id = 2;

                var entityChange1 = s.EntityChanges.Single(ec =>
                                                           ec.EntityTypeFullName == typeof(BlogPromotion).FullName &&
                                                           ec.EntityId == blog1Promotion2Id.ToJsonString(false, false)
                                                           );
                entityChange1.ChangeType.ShouldBe(EntityChangeType.Updated);
                entityChange1.PropertyChanges.Count.ShouldBe(1);

                var propertyChange1 = entityChange1.PropertyChanges.Single(pc => pc.PropertyName == nameof(BlogPromotion.Title));
                propertyChange1.OriginalValue.ShouldBe("test-promotion-2".ToJsonString(false, false));
                propertyChange1.NewValue.ShouldBe("test-promotion-2-updated".ToJsonString(false, false));
                propertyChange1.PropertyTypeFullName.ShouldBe(typeof(BlogPromotion).GetProperty(nameof(BlogPromotion.Title)).PropertyType.FullName);

                return(true);
            };

            _entityHistoryStore.Received().Save(Arg.Is <EntityChangeSet>(s => predicate(s)));
        }