I created a new entity. I would like to view the change logs for it.
It currently looks like this:
public class CourseDocument : FullAuditedEntity
{
public int CourseId { get; set; }
public Course Course { get; set; }
public int DocId { get; set; }
public Doc Doc { get; set; }
}
I've added the type to the tracked types:
namespace Bowie.Framework.Portal.EntityHistory
{
public static class EntityHistoryHelper
{
public const string EntityHistoryConfigurationName = "EntityHistory";
public static readonly Type[] HostSideTrackedTypes =
{
typeof(CourseDocument)
};
public static readonly Type[] TenantSideTrackedTypes =
{
typeof(CourseDocument)
};
public static readonly Type[] TrackedTypes =
HostSideTrackedTypes
.Concat(TenantSideTrackedTypes)
.GroupBy(type => type.FullName)
.Select(types => types.First())
.ToArray();
}
}
I then added the migration and updated the DB.
I was hoping to see the DocId and CourseID with their new values. Instead I just get no sign of them:
9 Answer(s)
-
0
What is your abp version? What is the Zero version? Ef 6 or ef core?
Please share the relevant code for the inserted entity.
-
0
Hi @jtallon, have you uncommented these lines for EntityHistory as part of the configuration?
https://github.com/aspnetzero/aspnet-zero-core/blob/e70c1dfad2f5f634a975948792239cc0bd1bfc10/aspnet-core/src/MyCompanyName.AbpZeroTemplate.EntityFrameworkCore/EntityFrameworkCore/AbpZeroTemplateEntityFrameworkCoreModule.cs#L43-L45
-
0
Hi @ryancyq,
In my portalEntityFrameworkCoreModule I have uncommented the two lines:
Configuration.EntityHistory.Selectors.Add("PortalEntities", EntityHistoryHelper.TrackedTypes); Configuration.CustomConfigProviders.Add(new EntityHistoryConfigProvider(Configuration));
Hi @maliming,
I am using ASPNetZero version: 6.8.0 EF: core
The create/edit code is:
[AbpAuthorize(AppPermissions.Pages_Courses_Create)] private async Task<int> Create(CreateOrEditCourseDto input) { var course = ObjectMapper.Map<Course>(input); var newCourseId = await _courseRepository.InsertAndGetIdAsync(course); return newCourseId; } [AbpAuthorize(AppPermissions.Pages_Courses_Edit)] private async Task<int> Update(CreateOrEditCourseDto input) { var courseEntity = ObjectMapper.Map<Course>(input); var course = await _courseRepository.UpdateAsync(courseEntity); return (int)input.Id; }
The CreateOrEditCourseDto in the code has public IEnumerable<int> DocumentIds { get; set; }
within my PortalDBContext I have the following:
protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity<CourseDocument>() .HasKey(bc => new { bc.CourseId, bc.DocId }); modelBuilder.Entity<CourseDocument>() .HasOne(bc => bc.Course) .WithMany(b => b.CourseDocuments) .HasForeignKey(bc => bc.CourseId); modelBuilder.Entity<CourseDocument>() .HasOne(bc => bc.Doc) .WithMany(c => c.CourseDocuments) .HasForeignKey(bc => bc.DocId); modelBuilder.Entity<CourseDocument>().Ignore(c => c.Id); /// }
-
0
hi @jtallon
Please share the complete code for the relevant entity and dto class.
Course CourseDocument Doc CreateOrEditCourseDto
-
0
hi @maliming, no problem:
Course
using Bowie.Framework.Portal.General; using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Abp.Domain.Entities.Auditing; using System.Collections.Generic; namespace Bowie.Framework.Portal.Training { [Table("Courses")] public class Course : FullAuditedEntity { [Required] public virtual string CourseName { get; set; } public virtual string Description { get; set; } public ICollection<CourseTrainer> CourseTrainers { get; set; } public ICollection<CourseDocument> CourseDocuments { get; set; } public ICollection<UserCourse> UserCourses { get; set; } public CourseCategory CourseCategory { get; set; } public virtual int? CourseCategoryId { get; set; } } }
CourseDocument
using Abp.Domain.Entities.Auditing; using Bowie.Framework.Portal.Document; namespace Bowie.Framework.Portal.Training { public class CourseDocument : FullAuditedEntity { public int CourseId { get; set; } public Course Course { get; set; } public int DocId { get; set; } public Doc Doc { get; set; } } }
Doc
using System; using Bowie.Framework.Portal.Authorization.Users; using Bowie.Framework.Portal.Training; using Bowie.Framework.Portal.General; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Abp.Domain.Entities.Auditing; using System.Collections.Generic; using System.Linq; using Bowie.Framework.Portal.CommentThreads; using JetBrains.Annotations; namespace Bowie.Framework.Portal.Document { [Table("Docs")] public class Doc : FullAuditedEntity { [Required] public virtual string ReferenceID { get; set; } [Required] public virtual string Title { get; set; } public ICollection<CourseDocument> CourseDocuments { get; set; } public ICollection<DocumentTrainer> DocumentTrainers { get; set; } public ICollection<DocumentPosition> DocumentPositions { get; set; } public ICollection<DocumentApprover> DocumentApprovers { get; set; } } }
CreateOrEditCourseDto
using System; using Abp.Application.Services.Dto; using System.ComponentModel.DataAnnotations; using System.Collections.Generic; namespace Bowie.Framework.Portal.Training.Dtos { public class CreateOrEditCourseDto : EntityDto<int?> { [Required] public string CourseName { get; set; } public string Description { get; set; } public IEnumerable<int> DocumentIds { get; set; } public IEnumerable<int> TraineeIds { get; set; } //user public IEnumerable<int> TrainerIds { get; set; } public int? CourseCategoryId { get; set; } } }
-
0
ObjectMapper.Map<Course>(input);
Please share the mapping configuration of automapper
-
0
thanks @maliming, here it is:
configuration.CreateMap<Course, CreateOrEditCourseDto>() .ForSourceMember(course => course.UserCourses, options => options.DoNotValidate()) .ForSourceMember(course => course.CourseTrainers, options => options.DoNotValidate()) .ForSourceMember(course => course.CourseDocuments, options => options.DoNotValidate()) ; configuration.CreateMap<CreateOrEditCourseDto, Course>() .ForMember(course => course.UserCourses, opt => opt.MapFrom(input => input.TraineeIds .Select(traineeId => new UserCourse { CourseId = input.Id ?? 0, UserId = traineeId }).ToList())) .ForMember(course => course.CourseDocuments, opt => opt.MapFrom(src => src.DocumentIds .Select(documentId => new CourseDocument { CourseId = src.Id ?? 0, DocId = documentId }))) .ForMember(course => course.CourseTrainers, opt => opt.MapFrom(src => src.TrainerIds .Select(trainerId => new CourseTrainer { CourseId = src.Id ?? 0, TrainerId = trainerId }))) ; configuration.CreateMap<Course, CourseDto>() .ForSourceMember(course => course.UserCourses, options => options.DoNotValidate()) .ForSourceMember(course => course.CourseTrainers, options => options.DoNotValidate()) .ForSourceMember(course => course.CourseDocuments, options => options.DoNotValidate()) ;
-
0
hi @jtallon
var newCourseId = await _courseRepository.InsertAndGetIdAsync(course);
CourseDocument won't get CourseId until the transaction is complete. You can consider inserting CourseDocument after getting the CourseId.
Fake code :
/*configuration.CreateMap<CreateOrEditCourseDto, Course>().ForMember(course => course.CourseDocuments, opt => opt.Ignore());*/ var course = ObjectMapper.Map<Course>(input); var newCourseId = await _courseRepository.InsertAndGetIdAsync(course); var courseDocuments = input.DocumentIds.Select(x => new CourseDocument() { CourseId = newCourseId }).ToList(); foreach (var courseDocument in courseDocuments) { await _courseDocumentRepository.InsertAsync(courseDocument); }
-
1
Thanks maliming, that makes sense. I will try that. I appreciate your patience.