繁体   English   中英

asp.net 样板错误地将实体保存为已删除

[英]asp.net boilerplate incorrectly saving entity as deleted

这是我在这里的第一篇文章,如果我没有提供足够的信息,请见谅。

我们使用 ABP v5.1 和 SQL 服务器数据库。 我们有一个从FullAuditedEntity<int>继承的Message实体,它具有消息 state、类型和关联公司的各种 ID。

要获取与 state 关联的值并键入 id,我们从数据库中的具有 Id、Group 和 Title 列的表中进行查找。

用于消息的 CRUD 操作的 class 是MessageAppService ,它继承自AsyncCrudAppService并具有对 create 和 update 的覆盖,在使用查找值进行一些输入操作后,它还会调用覆盖的基本方法。

问题是,当我向调用MessageAppService.UpdateAsync的消息提交更新时,它会将IsDeleted boolean 在输入中设置为 false 时设置为 true。 只有当我尝试从数据库中查找时才会发生这种情况。 注释掉代码以获取查找会导致预期的行为。

我将AsyncCrudAppService.UpdateAsync的代码复制到我的代码中,以查看将IsDeleted更改为false的位置,并在await CurrentUnitOfWork.SaveChangesAsync()调用中对其进行更改。

我怎样才能阻止它在显然不应该的情况下将消息标记为已删除?

以下是相关代码:

消息应用服务

public class MessageAppService : AsyncCrudAppService<Message, MessageDto, int, PagedMessageResultRequestDto,
        CreateUpdateMessageDto, CreateUpdateMessageDto>, IMessageAppService
    {
        private readonly IRepository<Message> _messageRepository;
        private readonly MessageGroupAppService _messageGroupAppService;
        private readonly RecipientGroupAppService _recipientGroupAppService;
        private readonly MessageRecipientAppService _messageRecipientAppService;
        private readonly RecipientAppService _recipientAppService;
        private readonly RoleManager _roleManager;
        private readonly UserManager _userManager;
        private readonly INotificationPublisher _notificationPublisher;
        private readonly IConfiguration _configuration;
        private readonly LookUpAppService _lookUpAppService;

        public MessageAppService(IRepository<Message> messageRepository,
                                MessageGroupAppService messageGroupAppService,
                                RecipientGroupAppService recipientGroupAppService,
                                MessageRecipientAppService messageRecipientAppService,
                                RecipientAppService recipientAppService,
                                RoleManager roleManager,
                                UserManager userManager,
                                INotificationPublisher notificationPublisher,
                                IConfiguration configuration,
                                LookUpAppService lookUpAppService)
            : base(messageRepository)
        {
            _messageRepository = messageRepository;
            _messageGroupAppService = messageGroupAppService;
            _recipientGroupAppService = recipientGroupAppService;
            _messageRecipientAppService = messageRecipientAppService;
            _recipientAppService = recipientAppService;
            _roleManager = roleManager;
            _userManager = userManager;
            _notificationPublisher = notificationPublisher;
            _configuration = configuration;
            _lookUpAppService = lookUpAppService;
        }

        public override async Task<MessageDto> CreateAsync(CreateUpdateMessageDto input)
        {
            return await ProcessMessage(input, true);
        }

        public override async Task<MessageDto> UpdateAsync(CreateUpdateMessageDto input)
        {
            return await ProcessMessage(input, false);
        }

        private async Task<MessageDto> ProcessMessage(CreateUpdateMessageDto input, bool create)
        {
            // Calling this causes `base.UpdateAsync` to set `IsDeleted` to `true`
            var messageState = (await _lookUpAppService.GetLookup("MessageState", input.StateLookUpId)).Title;

            var emailApprovers = false;
            var sendMessage = false;

            switch (messageState)
            {
                case "Pending":
                    // Calling this causes `base.UpdateAsync` to set `IsDeleted` to `true`
                    var company = (await _lookUpAppService.GetLookup("Company", input.CompanyLookUpId)).Title;

                    var permissionName = $"{company.ToUpper()}.Message.Approve";

                    if (!await PermissionChecker.IsGrantedAsync(permissionName))
                    {
                        emailApprovers = true;
                    }

                    break;
                case "Approved":
                    input.ApprovingUserId = AbpSession.UserId.Value;
                    sendMessage = true;
                    break;
            }

            MessageDto message;
            if (create)
            {
                message = await base.CreateAsync(input);
            }
            else
            {
                // `AsyncCrudAppService.UpdateAsync(input)` code from ABP git repo
                CheckUpdatePermission();

                var entity = await GetEntityByIdAsync(input.Id);

                MapToEntity(input, entity);

                // `entity` has correct values before this line
                await CurrentUnitOfWork.SaveChangesAsync();
                // `entity` is now soft deleted

                message = MapToEntityDto(entity);
            }

            if (input.GroupIds != null)
            {
                await _messageGroupAppService.UpdateMessageGroups(input.GroupIds, message.Id);
            }

            if (emailApprovers)
            {
                await EmailApprovers(message);
            }

            if (sendMessage)
            {
                await StartSendMessage((CreateUpdateMessageDto)message);
            }

            return message;
        }
    }
}

消息 class

[Table("BmMessages")]
public class Message : FullAuditedEntity<int>
{
    public const int MaxTitleLength = 50;
    public const int MaxBodyLength = 2000;

    [Required]
    [StringLength(MaxTitleLength)]
    public string Title { get; set; }

    [StringLength(MaxBodyLength)]
    public string Body { get; set; }

    [ForeignKey(nameof(ApprovingUserId))]
    public User ApprovingUser { get; set; }
    public long? ApprovingUserId { get; set; }

    [ForeignKey(nameof(StateLookUpId))]
    public LookUp StateLookUp { get; set; }
    public int StateLookUpId { get; set; }

    [ForeignKey(nameof(TypeLookUpId))]
    public LookUp TypeLookUp { get; set; }
    public int TypeLookUpId { get; set; }

    [ForeignKey(nameof(CompanyLookUpId))]
    public LookUp CompanyLookUp { get; set; }
    public int CompanyLookUpId { get; set; }

    public DateTime? ScheduledTime { get; set; }

    public Message(string title, string body = null)
    {
        Title = title;
        Body = body;
    }

    public Message(int typeLookUpId, int stateLookUpId, int companyLookUpId, string title, string body = null)
    {
        TypeLookUpId = typeLookUpId;
        StateLookUpId = stateLookUpId;
        CompanyLookUpId = companyLookUpId;
        Title = title;
        Body = body;
    }
}

消息Dto class

[AutoMapFrom(typeof(Message))]
public class MessageDto : FullAuditedEntityDto<int>
{
    public string Title { get; set; }
    
    public string Body { get; set; }

    public DateTime ScheduledTime { get; set; }

    public User ApprovingUser { get; set; }
    public long? ApprovingUserId { get; set; }

    public int StateLookUpId { get; set; }
    public LookUp StateLookUp { get; set; }

    public int TypeLookUpId { get; set; }
    public LookUp TypeLookUp { get; set; }

    public int CompanyLookUpId { get; set; }
    public LookUp CompanyLookUp { get; set; }

    public int[] GroupIds { get; set; }

    public int RecipientCount { get; set; }
}

CreateUpdateMessageDto class

[AutoMapTo(typeof(Message))]
public class CreateUpdateMessageDto : FullAuditedEntityDto<int>
{
    [Required]
    [MaxLength(Message.MaxTitleLength)]
    public string Title { get; set; }

    [Required]
    [MaxLength(Message.MaxBodyLength)]
    public string Body { get; set; }

    public DateTime ScheduledTime { get; set; }

    public User ApprovingUser { get; set; }
    public long? ApprovingUserId { get; set; }

    [Required]
    public int StateLookUpId { get; set; }
    public LookUp StateLookUp { get; set; }

    [Required]
    public int TypeLookUpId { get; set; }
    public LookUp TypeLookUp { get; set; }

    [Required]
    public int CompanyLookUpId { get; set; }
    public LookUp CompanyLookUp { get; set; }

    public int[] GroupIds { get; set; }

    public static explicit operator CreateUpdateMessageDto(MessageDto messageDto)
    {
        return new CreateUpdateMessageDto()
        {
            Id = messageDto.Id,
            Title = messageDto.Title,
            Body = messageDto.Body,
            ScheduledTime = messageDto.ScheduledTime,
            StateLookUpId = messageDto.StateLookUpId,
            StateLookUp = messageDto.StateLookUp,
            TypeLookUpId = messageDto.TypeLookUpId,
            TypeLookUp = messageDto.TypeLookUp,
            CompanyLookUpId = messageDto.CompanyLookUpId,
            CompanyLookUp = messageDto.CompanyLookUp,
            GroupIds = messageDto.GroupIds
        };
    }
}

查找 class

[Table("BmLookUps")]
public class LookUp : Entity
{
    [Required]
    public string Title { get; set; }

    [Required]
    public string Group { get; set; }

    public LookUp(string title, string group)
    {
        Title = title;
        Group = group;
    }
}

示例输入和结果(其中一些值是输入中的 null,因为它们是在服务器端填充的)

Input
CreateUpdateMessageDto

ApprovingUser         = null,
ApprovingUserId       = null,
Body                  = "Lorem Ipsum",
CompanyLookUp         = null,
CompanyLookUpId       = 17,
CreationTime          = {12/20/2020 11:52:08 PM},
CreatorUserId         = null,
DeleterUserId         = null,
DeletionTime          = null,
GroupIds              = {int[0]},
Id                    = 73,
IsDeleted             = false,
LastModificationTime  = null,
LastModifierUserId    = null,
ScheduledTime         = {12/29/2020 11:08:00 PM},
StateLookUp           = null,
StateLookUpId         = 1,
Title                 = "Test",
TypeLookUp            = null,
TypeLookUpId          = 8

Output
MessageDto

ApprovingUser         = null,
ApprovingUserId       = null,
Body                  = "Lorem Ipsum",
CompanyLookUp         = null,
CompanyLookUpId       = 17,
CreationTime          = {12/20/2020 11:52:08 PM},
CreatorUserId         = null,
DeleterUserId         = 6,
DeletionTime          = {12/21/2020 1:33:52 AM},
GroupIds              = null,
Id                    = 73,
IsDeleted             = true, // THIS SHOULD BE FALSE
LastModificationTime  = {12/20/2020 11:52:13 PM},
LastModifierUserId    = 6,
RecipientCount        = 0,
ScheduledTime         = {12/29/2020 11:08:00 PM},
StateLookUp           = null,
StateLookUpId         = 1,
Title                 = "Test",
TypeLookUp            = null,
TypeLookUpId          = 8

更新:根据要求,这里是GetLookup方法的相关代码。 它有2个重载。

public class LookUpAppService : ProjectAppServiceBase, ILookUpAppService
{
    private readonly IRepository<LookUp, int> _lookUpRepository;

    public LookUpAppService(IRepository<LookUp, int> lookUpRepository)
    {
        _lookUpRepository = lookUpRepository;
    }

    public async Task<LookUp> GetLookup(string Group, int Id)
    {
        return await _lookUpRepository.FirstOrDefaultAsync(l => l.Group == Group && l.Id == Id);
    }
        
    public async Task<LookUp> GetLookup(string Group, string Title)
    {
        return await _lookUpRepository.FirstOrDefaultAsync(l => l.Group == Group && l.Title == Title);
    }
}

这可能是由于被跟踪实体中的更改跟踪信息冲突。

添加.GetAll().AsNoTracking()如下:

public async Task<LookUp> GetLookup(string Group, int Id)
{
 // return await _lookUpRepository.FirstOrDefaultAsync(l => l.Group == Group && l.Id == Id);
    return await _lookUpRepository.GetAll().AsNoTracking().FirstOrDefaultAsync(l => l.Group == Group && l.Id == Id);
}
    
public async Task<LookUp> GetLookup(string Group, string Title)
{
 // return await _lookUpRepository.FirstOrDefaultAsync(l => l.Group == Group && l.Title == Title);
    return await _lookUpRepository.GetAll().AsNoTracking().FirstOrDefaultAsync(l => l.Group == Group && l.Title == Title);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM