簡體   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