2017-01-19 3 views
3

У меня очень странная проблема. Я создаю внешний интерфейс ASP.Net Core и API-интерфейс ASP.Net Core. API задней панели использует ядро ​​Entity Framework для сохранения.Попытка сопоставить один класс домена для просмотра класса модели пропускает свойства

Я использую класс модели представления для публикации данных с веб-сайта в API, затем я использую AutoMapper для сопоставления из класса модели представления класса сущности, чтобы передать его в репозиторий на основе EF. Это работало для двух других отношений модели представления/сущности в этом проекте, связанных с другими таблицами базы данных.

Однако я добавляю новую таблицу базы данных и связанную с ней модель модели/сущности класса, которая дает мне эту странную проблему.

С помощью этой конкретной связи модели объекта/вида Automapper выходит из строя без ошибок. Он просто пропускает любое свойство, которое не определено в классе сущности, с вопросительным знаком после типа данных (что делает свойство nullable).

Я создал метод ручной сопоставления свойств, один за другим, из класса модели представления в класс сущности, и я вижу ту же проблему, поэтому считаю, что это не проблема AutoMapper.

Вот мой класс сущности;

using System; 
using System.Collections.Generic; 

namespace API.Models 
{ 
    public partial class UserFeaturesEvs 
    { 
     public int UserId { get; set; } 
     public bool Active { get; set; } 
     public string LoginNickname { get; set; } 
     public string CarrierLoginName { get; set; } 
     public string CarrierLoginPassword { get; set; } 
     public int CarrierId { get; set; } 
     public int? CarrierLoginId { get; set; } 
     public string PermitNumber { get; set; } 
     public string PermitType { get; set; } 
     public string PermitName { get; set; } 
     public int? McdPrimaryId { get; set; } 
     public string Crid { get; set; } 
     public string CapsId { get; set; } 
     public bool? IsGovernment { get; set; } 
     public string CityStateOfPo { get; set; } 
     public string PoOfAccountZip { get; set; } 
     public string MasterMid { get; set; } 
     public string ChildMid { get; set; } 
     public string IndiciaText { get; set; } 
     public string LoginId { get; set; } 
     public string PostageType { get; set; } 
     public int? SiteId { get; set; } 
    } 
} 

И вот мой класс модели просмотра;

using System.ComponentModel.DataAnnotations; 

namespace API.ViewModels.EVS 
{ 
    public class UserFeaturesEvsViewModel 
    { 
     public bool Active { get; set; } 
     [Display(Name = "User ID")] 
     public int UserId { get; set; } 

     [Display(Name = "Carrier ID")] 
     [Required] 
     public int CarrierId { get; set; } 

     [Display(Name = "Site ID")] 
     public int SiteId { get; set; } 

     [Display(Name = "Nick Name")] 
     public string LoginNickname { get; set; } 

     [Display(Name = "Login Name")] 
     [Required] 
     public string CarrierLoginName { get; set; } 

     [Display(Name = "Password")] 
     [Required] 
     public string CarrierLoginPassword { get; set; } 

     [Display(Name = "Carrier Login ID")] 
     public int CarrierLoginId { get; set; } 

     [Display(Name = "MCD Primary ID")] 
     public int McdPrimaryId { get; set; } 

     [Display(Name = "Permit Number")] 
     public string PermitNumber { get; set; } 

     [Display(Name = "Permit Type")] 
     public string PermitType { get; set; } 

     [Required] 
     [Display(Name = "Permit Name")] 
     public string PermitName { get; set; } 

     [Display(Name = "CRID")] 
     public string Crid { get; set; } 

     [Display(Name = "CAPS ID")] 
     public string EvsCapsId { get; set; } 

     [Display(Name = "Government Permit")] 
     public bool EvsGovernmentPermit { get; set; } 

     [Display(Name = "PO of Account - City/State")] 
     public string EvsCityStateOfPo { get; set; } 

     [Display(Name = "PO of Account - Zipcode")] 
     public string EvsPoOfAccountZip { get; set; } 

     [Display(Name = "Master MID") 
     public string EvsMasterMid { get; set; } 

     [Display(Name = "Child ID")] 
     public string EvsChildMid { get; set; } 

     [Display(Name = "Indicia Text")] 
     public string EvsIndiciaText { get; set; } 

     [Display(Name = "Login ID")] 
     public string EvsLoginId { get; set; } 

     [Display(Name = "Postage Type")] 
     public string PostageType { get; set; } 

    } 
} 

Это метод теста, который я создал в классе контроллера API вручную карту из класса вида модели к классу сущностей

private UserFeaturesEvs MapUserFeaturesEvsViewModelToUserFeaturesEvs(UserFeaturesEvsViewModel a_model) 
    { 
     try 
     { 
      UserFeaturesEvs model = new UserFeaturesEvs(); 
      if (a_model != null) 
      { 
       model.SiteId = a_model.SiteId; 
       model.Active = a_model.Active; 
       model.UserId = a_model.UserId; 
       model.CarrierId = a_model.CarrierId; 
       model.LoginNickname = a_model.LoginNickname; 
       model.CarrierLoginName = a_model.CarrierLoginName; 
       model.CarrierLoginPassword = a_model.CarrierLoginPassword; 
       model.CarrierLoginId = a_model.CarrierLoginId; 
       model.McdPrimaryId = a_model.McdPrimaryId; 
       model.PermitNumber = a_model.PermitNumber; 
       model.PermitType = a_model.PermitType; 
       model.PermitName = a_model.PermitName; 
       model.Crid = a_model.Crid; 
       model.CapsId = a_model.EvsCapsId; 
       model.IsGovernment = a_model.EvsGovernmentPermit; 
       model.CityStateOfPo = a_model.EvsCityStateOfPo; 
       model.PoOfAccountZip = a_model.EvsPoOfAccountZip; 
       model.MasterMid = a_model.EvsMasterMid; 
       model.ChildMid = a_model.EvsChildMid; 
       model.IndiciaText = a_model.EvsIndiciaText; 
       model.LoginId = a_model.EvsLoginId; 
       model.PostageType = a_model.PostageType; 
      } 
      return model; 

     } 
     catch (Exception ex) 
     { 
      m_logger.LogError(1, ex, "An exception occurred in the MapUserFeaturesEvsViewModelToUserFeaturesEvs method while trying to map the UserFeaturesEvsViewModel [{VM}] to the UserFeaturesEvs Model.", a_model); 
      return null; 
     } 

Теперь я могу видеть, что проблема происходит, как я за один шаг в Visual Studio 2015, с помощью метода MapUserFeaturesEvsViewModelToUserFeaturesEvs с использованием F11. Как только я пройду мимо строки if (a_model! = Null), отладка останавливается только на строках для SiteId, CarrierLoginId, McdPrimaryId и EvsGovernmentPermit, пропуская все остальные. И возвращенный объект UserFeaturesEvs имеет только данные в этих 4 полях. Я подтвердил, что объект UserFeaturesEvsViewModel, переданный в метод, имеет данные во всех свойствах.

Свойства класса UserFeatruesEvs, которые являются успешно назначенными данными, являются только теми, у которых есть значения NULL, обозначенные символом? после типа данных, как показано в выдержках свойств из класса UserFeaturesEvs, ниже;

 public int? CarrierLoginId { get; set; } 
     public int? McdPrimaryId { get; set; } 
     public bool? IsGovernment { get; set; } 
     public int? SiteId { get; set; } 

Класс объекта, UserFeaturesEvs был сгенерирован из существующей таблицы базы данных, используя ..

dotnet ef dbcontext scaffold ... 

... команду.

Вышеуказанная команда командной строки также добавляет код ниже к классу DbContext ...

protected override void OnModelCreating(ModelBuilder modelBuilder) 
    { 
     modelBuilder.Entity<UserFeaturesEvs>(entity => 
     { 
      entity.HasKey(e => e.UserId) 
       .HasName("PK_UserFeatures_EVS"); 

      entity.ToTable("UserFeatures_EVS"); 

      entity.Property(e => e.UserId) 
       .HasColumnName("UserID") 
       .ValueGeneratedNever(); 

      entity.Property(e => e.CapsId) 
       .HasColumnName("CapsID") 
       .HasColumnType("varchar(50)"); 

      entity.Property(e => e.CarrierId).HasColumnName("CarrierID"); 

      entity.Property(e => e.CarrierLoginId).HasColumnName("CarrierLoginID"); 

      entity.Property(e => e.CarrierLoginName) 
       .IsRequired() 
       .HasColumnType("varchar(50)"); 

      entity.Property(e => e.CarrierLoginPassword) 
       .IsRequired() 
       .HasColumnType("varchar(50)"); 

      entity.Property(e => e.ChildMid) 
       .HasColumnName("ChildMID") 
       .HasColumnType("varchar(50)"); 

      entity.Property(e => e.CityStateOfPo) 
       .HasColumnName("CityStateOfPO") 
       .HasColumnType("varchar(50)"); 

      entity.Property(e => e.Crid) 
       .HasColumnName("CRID") 
       .HasColumnType("varchar(50)"); 

      entity.Property(e => e.IndiciaText).HasColumnType("varchar(50)"); 

      entity.Property(e => e.LoginId).HasColumnType("varchar(50)"); 

      entity.Property(e => e.LoginNickname).HasColumnType("varchar(50)"); 

      entity.Property(e => e.MasterMid) 
       .HasColumnName("MasterMID") 
       .HasColumnType("varchar(50)"); 

      entity.Property(e => e.McdPrimaryId).HasColumnName("MCDPrimaryID"); 

      entity.Property(e => e.PermitName).HasColumnType("varchar(50)"); 

      entity.Property(e => e.PermitNumber).HasColumnType("varchar(50)"); 

      entity.Property(e => e.PermitType).HasColumnType("varchar(50)"); 

      entity.Property(e => e.PoOfAccountZip) 
       .HasColumnName("PoOfAccountZip") 
       .HasColumnType("varchar(50)"); 

      entity.Property(e => e.PostageType).HasColumnType("varchar(50)"); 

      entity.Property(e => e.SiteId).HasColumnName("SiteID"); 
     }); 

    } 

    public virtual DbSet<UserFeaturesEvs> UserFeaturesEvs { get; set; } 

. 
. 
. 

Я не могу увидеть что-нибудь, что является причиной этой проблемы и, как я уже говорил ранее, я использовал этот такой же метод класса класса/вида класса объектов с двумя другими таблицами базы данных без проблем.

Весь код, о котором я говорю выше, находится в проекте API ASP.Net Core.

Я попытался удалить?из объявлений типа данных в свойствах класса UserFeaturesEvs, и когда я это сделал, отладчик просто пропустил все назначения свойств и вернул все нулевые данные из метода сопоставления.

EDIT: Дальнейший анализ показывает, что проблема связана с UserFeaturesEvsViewModel. Я могу статически присваивать значения экземпляру объекта UserFeaturesEvs в методе MapUserFeaturesEvsViewModelToUserFeaturesEvs и он не пропускает присваивания свойств, которые не имеют? после их объявления типа данных. Поскольку это API, UserFeatruesEvsViewModel исходит из метода Create в контроллере API.

[HttpPost("")] 
    public IActionResult Create([FromBody]UserFeaturesEvsViewModel a_vm) 
    { 
     try 
     { 
      //Test assignment of vm to local variables 
      int SiteId = a_vm.SiteId; // This gets skipped 
      bool Active = a_vm.Active; // This gets skipped 
      int UserId = a_vm.UserId; // This gets skipped 
      int CarrierId = a_vm.CarrierId; // This gets skipped 
      string LoginNickname = a_vm.LoginNickname; // This gets skipped 

      if (ModelState.IsValid) 
      { 
       UserFeaturesEvs model = MapUserFeaturesEvsViewModelToUserFeaturesEvs(a_vm); 

       //UserFeaturesEvs model = Mapper.Map<UserFeaturesEvs>(a_vm); 
       . 
       . 
       . 

Это образец JSON я отправляю в качестве приложения/JSON к контроллеру API из приложения Google Chrome Почтальон

{ 
    "active": true, 
    "userId": 1, 
    "carrierId": 1, 
    "siteId": 1, 
    "loginNickname": "testNickname", 
    "carrierLoginName": "testLoginName", 
    "carrierLoginPassword": "testLoginPassword", 
    "carrierLoginId": 0, 
    "mcdPrimaryId": 0, 
    "permitNumber": "123456", 
    "permitType": "", 
    "permitName": "UserID1-123456", 
    "crid": "11", 
    "evsCapsId": "112233", 
    "evsGovernmentPermit": false, 
    "evsCityStateOfPo": "Somewhere, NY", 
    "evsPoOfAccountZip": "90210", 
    "evsMasterMid": "654321", 
    "evsChildMid": "654322", 
    "evsIndiciaText": "Test", 
    "evsLoginId": "", 
    "postageType": "P" 
} 

Когда я осматриваю a_vm в отладчике, я вижу данные, которые я отправляю, и он, похоже, находится в структуре класса UserVeaturesEvsViewModel. Однако, когда я пытаюсь просто присваивать свойства переменной a_vm локальным переменным в начале метода Create, как показано выше, эти назначения также просто пропускаются отладчиком (даже если я поставил точку останова на назначения) как это происходит в методе MapUserFeaturesEvsViewModelToUserFeaturesEvs.

В других контроллерах API, где у меня нет этой проблемы, я передаю объект a_vm в свой репозиторий Entity Framework. Например, код, приведенный ниже в другом контроллере этого же API, отлично работает.

[HttpPost("")] 
    public IActionResult Create([FromBody]MerSettingsViewModel a_vm) 
    { 
     try 
     { 
      if (ModelState.IsValid) 
      { 
       MailEventsRetrieverSettings settings = Mapper.Map<MailEventsRetrieverSettings>(a_vm); 
       Task<MailEventsRetrieverSettings> task = m_cdiMppsRepository.AddMailEventsRetrieverSettingsAsync(settings); 
       MailEventsRetrieverSettings response = task.Result; 
       if (response != null) 
       { 
        return Ok(response); 
       } 
      } 
      return BadRequest(ModelState); 
     } 
     catch (Exception ex) 
     { 
      m_logger.LogError(1, ex, "Could not create new MailEventsRetrieverSettings record for the following object [{@VM}] to the database", a_vm); 
      return Json(new { Message = ex.Message }); 
     } 
    } 

Таким образом, проблема, кажется, идет от того, как объект автоматически десериализованное из тела HttpPost в методе Create. Несмотря на то, что в отладчике я вижу значения в a_vm и, похоже, он структурирован правильно, я не могу прямо присваивать значения этих свойств другому свойству класса или локальной переменной, если свойство класса или локальная переменная не определены как обнуляемый.

Любые идеи?

+0

Значит, он работает только для свойств с нулевым значением? – CodingYoshi

+0

Они должны удалить всю вашу папку bin и выполнить перестройку и повторить попытку. – CodingYoshi

+0

Почему ваш класс модели частично? Не могли бы вы показать другие части этого класса? –

ответ

0

Я не очень хорошо знаком с Automapper, но читать над их вики сказано:

AutoMapper будет игнорировать нулевые эталонные исключения, когда отображение вашего источника к цели. Это по дизайну.

Вы проверяете объект уже, если видите, что значения, которые вы проходите, приближаются к нулю.

+0

Я убедился, что все свойства экземпляра объекта UserFeaturesEvsViewModel, который я передаю методу, имеют значения, как указано в моем первоначальном сообщении. Они просто не привязаны к свойствам экземпляра объекта UserFeaturesEvs, если только это свойство в UserFeatruesEvs не имеет знака вопроса после его объявления типа данных в классе объекта. – EiEiGuy

+0

Что касается Automapper, он может игнорировать нулевые ссылочные исключения, но в примере, который я показываю в своем сообщении, я не использую Automapper. Я вручную сопоставляю свойства между двумя объектами класса, чтобы попытаться определить, почему Automapper терпит неудачу, и я получаю такое же поведение без Automapper. – EiEiGuy

+0

@joseph, код, о котором идет речь, не использует automapper, и даже если он был сбойными свойствами, это не ссылочные типы. – CodingYoshi

Смежные вопросы