AutoMapper DTO 未正确序列化派生类插入

问题描述 投票:0回答:1

我在应用程序中插入派生类型的警报时遇到问题。我有一个基类

Alert
及其相应的 DTO,以及一个派生类
OperationalAlert
(它扩展了
Alert
)和一个
OperationalAlertDto
。插入由
AlertTypeId
识别。但是,当我尝试插入
OperationalAlert
的实例时,这些值将显示为 null。我已确认所有属性都已正确映射到我的 AutoMapper 配置中,并且 DTO 和
OperationalAlertDto
中的必要字段均已填充。尽管如此,插入仍然失败。有没有人遇到过类似的问题或可以提供如何解决此问题的指导?

public async Task<Alert> CreateAlertAsync(AlertDTO alertDto)
{
    if (alertDto == null)
    {
        throw new ArgumentNullException(nameof(alertDto), "Alert DTO cannot be null.");
    }

    Alert alert = alertDto.AlertTypeId switch
    {
       1 => _mapper.Map<AlertInformational>(alertDto) as Alert,
       2 => _mapper.Map<AlertIncident>(alertDto) as Alert,
       3 => _mapper.Map<OperationalAlert>(alertDto) as Alert,
       4 => _mapper.Map<OperationalAlert>(alertDto) as Alert,
       _ => throw new ArgumentOutOfRangeException(nameof(alertDto.AlertTypesId), "Invalid alert type"),
    };

    var addedAlertType = await _alertRepository.AddAsync(alert);
    return addedAlertType;
}

这是错误跟踪:

public class Alert
{
    public int Id { get; set; }
    public int AlertTypeId{ get; set; }
    public int CreatorId { get; set; }
    public string Name { get; set; }
    public string Title { get; set; }
   
    public int TemplateRefId { get; set; }
    public int DepartmentId { get; set; }
    public bool IsProcessChanged { get; set; }
    public bool? IsPermanent { get; set; }
    public virtual Department? Department { get; set; }
    public virtual User? Creator { get; set; }
    public virtual AlertType? Type { get; set; }
    public virtual Template? Template { get; set; }
    public int ChangeDetailId { get; set; }
    public virtual ChangeDetail? ChangeDetail { get; set; }
    public virtual ICollection<Recipient>? AlertRecipients { get; set; }
    public virtual ICollection<Attachment>? AlertAttachments { get; set; }
    public virtual ICollection<Update>? AlertUpdates { get; set; }
    public virtual ICollection<CustomLog>? LogEntries { get; set; }
    public virtual ICollection<OperationDetail>? OperationDetails { get; set; }
}
using System.Collections.Generic;

namespace YourNamespace.Alerting.Domain.Model.Dto
{
    public class AlertDTO
    {
        public int Id { get; set; } 
        public int AlertTypeId { get; set; } 
        public int CreatorId { get; set; } 
        public string UserName { get; set; } 
        public string Title { get; set; } 
        public string Content { get; set; } 
        public int TemplateRefId { get; set; } 
        public int DepartmentId { get; set; } 
        public bool IsProcessChanged { get; set; } 
        public bool? IsPermanent { get; set; } 
        public virtual ICollection<RecipientDto>? Recipients { get; set; } 
        public virtual ICollection<UpdateDto>? Updates { get; set; } 
        public virtual ICollection<AttachmentDto>? Attachments { get; set; } 
        public virtual ICollection<OperationDto>? Operations { get; set; } 
        public virtual ICollection<LogDto>? Logs { get; set; } 
        public int ChangeDetailId { get; set; } 
    }

    public class ChangeDetailDto
    {
        public int Id { get; set; } 
        public string Name { get; set; } 
    }

    public class RecipientDto
    {
        public int AlertId { get; set; } 
        public int RecipientId { get; set; } 
    }

    public class UpdateDto
    {
        public int Id { get; set; } 
        public string Message { get; set; } 
        public int AlertId { get; set; } 
        public int TypeId { get; set; } 
    }
}
public class OperationalAlert : Alert
{
    public AlertState State { get; set; }
    public UrgencyLevel Urgency { get; set; }
    public bool IsEnabled { get; set; }
    public DateTime CreatedOn { get; set; }
    public string Content { get; set; }
    public DateTime ExpiresOn { get; set; }
    public string Location { get; set; }
    public string MessageContent { get; set; }
    public string Description { get; set; }
    public DateTime OccurrenceTime { get; set; }
    public string Method { get; set; }
    public string Reason { get; set; }
    public virtual ICollection<OperationalAlertRevision>? Revisions { get; set; }
}

public enum AlertState
{
    Active,
    Inactive,
    Expired,
    Pending,
    Resolved
}

public enum UrgencyLevel
{
    Low,
    Medium,
    High,
    Critical
}

这是产品警报的 dto :

public class OperationalAlertDto : AlertDTO
{
    public int Id { get; set; }
    public string Title { get; set; }
    public AlertState State { get; set; }
    public UrgencyLevel Urgency { get; set; }
    public bool IsEnabled { get; set; }
    public string Content { get; set; }
    public DateTime CreatedOn { get; set; }
    public DateTime ExpiresOn { get; set; }
    public string Description { get; set; }
    public DateTime OccurrenceTime { get; set; }
    public string Method { get; set; }
    public string Reason { get; set; }
    public string Location { get; set; }
    public string MessageContent { get; set; }

    public List<OperationalAlertRevisionDto>? Revisions { get; set; }
}

public class OperationalAlertRevisionDto
{
    public int RevisionId { get; set; }
    public bool IsCurrent { get; set; }
    public int AlertId { get; set; }
    public int AlertTypeId { get; set; }
}

public AutoMapperProfile()
{
        CreateMap<Department, DepartmentDTO>().ReverseMap();
        CreateMap<TemplateType, TemplateTypeDTO>().ReverseMap();
        CreateMap<Template, TemplateDTO>().ReverseMap();
        CreateMap<User, UserDTO>();

        CreateMap<OperationalAlertDto, OperationalAlert>()
            .IncludeBase<AlertDTO, Alert>();

        CreateMap<AlertDTO, AlertInformational>();
        CreateMap<AlertDTO, AlertIncident>();
        CreateMap<AlertDTO, OperationalAlert>().ReverseMap();
        CreateMap<OperationalAlertDto, OperationalAlert>().ReverseMap();
        CreateMap<OperationalAlertDto, OperationalAlert>().ReverseMap();

        CreateMap<Alert, AlertDTO>()
            .ForMember(dest => dest.UserName, opt => opt.MapFrom(src => src.user != null ? src.user.UserName : null))
            .Include<OperationalAlert, OperationalAlertDto>()
            .ReverseMap();

       
        CreateMap<AlertRecipient, AlertRecipientDto>().ReverseMap();
        CreateMap<AlertUpdate, AlertUpdateDto>().ReverseMap();
}

这是我的鉴别器定义:

builder.Services.AddControllers()
    .AddNewtonsoftJson(options =>
    {
        options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        options.SerializerSettings.Converters.Add(
            JsonSubtypesConverterBuilder
                .Of(typeof(Alert), nameof(Alert.AlertTypeId I))
                .RegisterSubtype(typeof(AlertInformational), 1)
                .RegisterSubtype(typeof(AlertIncident), 2)
                .RegisterSubtype(typeof(OperationalAlert), 4) 
                .SerializeDiscriminatorProperty()
                .Build());
    });
options.UseAllOfToExtendReferenceSchemas();
options.UseAllOfForInheritance();
options.UseOneOfForPolymorphism();
options.SelectDiscriminatorNameUsing(type =>
{
    return type.Name switch
    {
        nameof(Alert) => "AlertTypeId",
        _ => null
    };
});

这里是错误跟踪,表明值不能插入为空,这表明数据的映射没有被正确识别,导致值没有被插入。

Microsoft.EntityFrameworkCore.Update[10000]
      An exception occurred in the database while saving changes for context type 'alertapp_Alerting.Persistence.Context.alertappAlertingDbContext'.
      Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
       ---> MySqlConnector.MySqlException (0x80004005): Column 'Content' cannot be null
         at MySqlConnector.Core.ServerSession.ReceiveReplyAsync(IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/Core/ServerSession.cs:line 894
         at MySqlConnector.Core.ResultSet.ReadResultSetHeaderAsync(IOBehavior ioBehavior) in /_/src/MySqlConnector/Core/ResultSet.cs:line 37
         at MySqlConnector.MySqlDataReader.ActivateResultSet(CancellationToken cancellationToken) in /_/src/MySqlConnector/MySqlDataReader.cs:line 130
         at MySqlConnector.MySqlDataReader.NextResultAsync(IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/MySqlDataReader.cs:line 90
         at MySqlConnector.MySqlDataReader.NextResultAsync(CancellationToken cancellationToken) in /_/src/MySqlConnector/MySqlDataReader.cs:line 49
         at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeAsync(RelationalDataReader reader, CancellationToken cancellationToken)
         --- End of inner exception stack trace ---
         at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeAsync(RelationalDataReader reader, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
         at Pomelo.EntityFrameworkCore.MySql.Storage.Internal.MySqlExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
      Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
       ---> MySqlConnector.MySqlException (0x80004005): Column 'Content' cannot be null
         at MySqlConnector.Core.ServerSession.ReceiveReplyAsync(IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/Core/ServerSession.cs:line 894
         at MySqlConnector.Core.ResultSet.ReadResultSetHeaderAsync(IOBehavior ioBehavior) in /_/src/MySqlConnector/Core/ResultSet.cs:line 37
         at MySqlConnector.MySqlDataReader.ActivateResultSet(CancellationToken cancellationToken) in /_/src/MySqlConnector/MySqlDataReader.cs:line 130
         at MySqlConnector.MySqlDataReader.NextResultAsync(IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/MySqlDataReader.cs:line 90
         at MySqlConnector.MySqlDataReader.NextResultAsync(CancellationToken cancellationToken) in /_/src/MySqlConnector/MySqlDataReader.cs:line 49
         at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeAsync(RelationalDataReader reader, CancellationToken cancellationToken)
         --- End of inner exception stack trace ---
         at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeAsync(RelationalDataReader reader, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
         at Pomelo.EntityFrameworkCore.MySql.Storage.Internal.MySqlExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
fail: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[1]
      An unhandled exception has occurred while executing the request.
      System.InvalidOperationException: An error occurred while adding the alert and sending the email.
       ---> Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
       ---> MySqlConnector.MySqlException (0x80004005): Column 'Content' cannot be null
         at MySqlConnector.Core.ServerSession.ReceiveReplyAsync(IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/Core/ServerSession.cs:line 894
         at MySqlConnector.Core.ResultSet.ReadResultSetHeaderAsync(IOBehavior ioBehavior) in /_/src/MySqlConnector/Core/ResultSet.cs:line 37
         at MySqlConnector.MySqlDataReader.ActivateResultSet(CancellationToken cancellationToken) in /_/src/MySqlConnector/MySqlDataReader.cs:line 130
         at MySqlConnector.MySqlDataReader.NextResultAsync(IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/MySqlDataReader.cs:line 90
         at MySqlConnector.MySqlDataReader.NextResultAsync(CancellationToken cancellationToken) in /_/src/MySqlConnector/MySqlDataReader.cs:line 49
         at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeAsync(RelationalDataReader reader, CancellationToken cancellationToken)
         --- End of inner exception stack trace ---
         at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeAsync(RelationalDataReader reader, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
         at Pomelo.EntityFrameworkCore.MySql.Storage.Internal.MySqlExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
         at alertapp_Alerting.Persistence.Repositories.AlertRepository.AddAsync(Alert alert) in C:\Users\e10133604\Desktop\alertappalertingapi\alertapp-Alerting\Persistence\Repositories\AlertRepository.cs:line 47
         --- End of inner exception stack trace ---
         at alertapp_Alerting.Persistence.Repositories.AlertRepository.AddAsync(Alert alert) in C:\Users\e10133604\Desktop\alertappalertingapi\alertapp-Alerting\Persistence\Repositories\AlertRepository.cs:line 54
         at alertapp_Alerting.Services.AlertService.CreateAlertAsync(AlertDTO alertDto) in C:\Users\e10133604\Desktop\alertappalertingapi\alertapp-Alerting\Services\AlertService.cs:line 83
         at alertapp_Alerting.Controllers.AlertController.CreateAlertWithFile(AlertDTO alert) in C:\Users\e10133604\Desktop\alertappalertingapi\alertapp-Alerting\Controllers\AlertController.cs:line 52
         at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
         at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
         at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
         at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
         at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
         at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddlewareImpl.<Invoke>g__Awaited|10_0(ExceptionHandlerMiddlewareImpl middleware, HttpContext context, Task task)
fail: alertapp_Alerting.Exceptions.GeneralExceptionHandler[0]
      Something went wrong..
      System.InvalidOperationException: An error occurred while adding the alert and sending the email.
       ---> Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
       ---> MySqlConnector.MySqlException (0x80004005): Column 'Content' cannot be null
         at MySqlConnector.Core.ServerSession.ReceiveReplyAsync(IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/Core/ServerSession.cs:line 894
         at MySqlConnector.Core.ResultSet.ReadResultSetHeaderAsync(IOBehavior ioBehavior) in /_/src/MySqlConnector/Core/ResultSet.cs:line 37
         at MySqlConnector.MySqlDataReader.ActivateResultSet(CancellationToken cancellationToken) in /_/src/MySqlConnector/MySqlDataReader.cs:line 130
         at MySqlConnector.MySqlDataReader.NextResultAsync(IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/MySqlDataReader.cs:line 90
         at MySqlConnector.MySqlDataReader.NextResultAsync(CancellationToken cancellationToken) in /_/src/MySqlConnector/MySqlDataReader.cs:line 49
         at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeAsync(RelationalDataReader reader, CancellationToken cancellationToken)
         --- End of inner exception stack trace ---
         at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeAsync(RelationalDataReader reader, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
         at Pomelo.EntityFrameworkCore.MySql.Storage.Internal.MySqlExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
         at alertapp_Alerting.Persistence.Repositories.AlertRepository.AddAsync(Alert alert) in C:\Users\e10133604\Desktop\alertappalertingapi\alertapp-Alerting\Persistence\Repositories\AlertRepository.cs:line 47
         --- End of inner exception stack trace ---
         at alertapp_Alerting.Persistence.Repositories.AlertRepository.AddAsync(Alert alert) in C:\Users\e10133604\Desktop\alertappalertingapi\alertapp-Alerting\Persistence\Repositories\AlertRepository.cs:line 54
         at alertapp_Alerting.Services.AlertService.CreateAlertAsync(AlertDTO alertDto) in C:\Users\e10133604\Desktop\alertappalertingapi\alertapp-Alerting\Services\AlertService.cs:line 83
         at alertapp_Alerting.Controllers.AlertController.CreateAlertWithFile(AlertDTO alert) in C:\Users\e10133604\Desktop\alertappalertingapi\alertapp-Alerting\Controllers\AlertController.cs:line 52
         at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
         at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
         at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
c# .net asp.net-core entity-framework-core automapper
1个回答
0
投票

问题在于当您想要多态参数时控制器操作如何从请求填充模型。通常,如果您有一个接受基类 AlertDTO 的函数,并且您的调用代码构造了一个 OperationalAlertDTO、ProductionAlertDTO 或任何其他子类,并且您调用接受参数作为 AlertDTO 的方法,则该代码将按您的预期工作,因为底层对象“是一个”OperationalAlertDTO 等。因此,重新转换为子类的条件代码将起作用。对于多态方法来说,使用条件代码来处理特定的子类并不是一个好的实现,但是代码会按照您的预期工作。

但是,对于控制器操作,这将不起作用。当您创建接受 ActionDTO 的控制器操作时,如果该操作接受 ActionDTO,则对控制器的视图(表单或 Ajax/Fetch)调用是否填充足够的字段来创建 OperationalAlertDTO 或任何其他子类并不重要。 ActionDTO 控制器将仅尝试创建和填充 ActionDTO,而不是任何子类。

控制器操作有两个选项,具体取决于您构建应用程序的方式。如果您的视图等特定于警报类型,因此您的视图希望与 OperationalAlertDTO 一起使用,而不是与 ProductionAlertDTO 一起使用的其他视图,那么一个简单的解决方案是按具体子类类型拆分控制器操作,因为您正在有条件地处理示例中的每个子类。例如:

public async Task<Alert> CreateOperationalAlertAsync(OperationalAlertDTO alertDto)

public async Task<Alert> CreateProductionAlertAsync(ProductionAlertDTO alertDto)

然后,这些方法可以使用从 OperationalAlertDTO -> OperationalAlert 等正确的映射,不会出现问题,因为 MVC 会将从视图/客户端传递的任何数据解析为正确的具体 DTO 类型。

如果您希望对传入的这些警报的所有实例采取共同行为,您可以拥有一个共享私有函数,该函数接受来自每个警报的 AlertDto 作为

AlertDTO
,并且这些方法都可以调用该共享方法。只是避免将条件重铸放入常见的基类操作中。接受基类(或接口)的方法应该只关心每个调用的参数是该基类型。

另一种选择是连接自定义模型绑定器并在视图数据中公开具体类型,如下所示: 多态模型绑定带有列表和编辑器模板的ViewModel

此方法允许使用OperationalAlertDTO 或ProductionAlertDTO 填充视图,从而公开具体类型的隐藏输入。自定义模型绑定程序在 ASP.Net MVC 中注册,以便当它具有需要 AlertDTO 类型的控制器方法时,它会在视图数据中查找 ModelType 并使用它来构造适当的具体子类。

© www.soinside.com 2019 - 2024. All rights reserved.