2017-01-19 71 views
3

我有一個很奇怪的問題。我正在創建一個ASP.Net Core前端網站和一個ASP.Net Core後端API。後端API使用Entity Framework Core來實現持久性。試圖從一個領域類映射到視圖模型類跳過屬性

我用一個視圖模型類,從網站的數據發佈到API,然後我用AutoMapper從視圖模型類的實體類映射到它傳遞給基於EF庫。這適用於此項目中與其他數據庫表有關的另外兩個視圖模型/實體類關係。

不過,我加入了一個新的數據庫表和相關視圖模型/實體類集合是給我這個奇怪的問題。

通過這種特定的實體/視圖模型關係,Automapper失敗並且沒有錯誤。它只是跳過實體類中未定義的任何屬性,並在數據類型之後帶有問號(使屬性可爲空)。

我創建了一個方法的屬性,一個一個手動映射,從視圖模型類的實體類,我看到了同樣的問題,所以我認爲這是沒有具體的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中,通過使用F11的MapUserFeaturesEvsViewModelToUserFeaturesEvs方法。一旦我越過if(a_model!= null)行,調試僅停止在SiteId,CarrierLoginId,McdPrimaryId和EvsGovernmentPermit的行上,跳過所有其他行。並且返回的UserFeaturesEvs對象只在這4個字段中有數據。我確認傳入該方法的UserFeaturesEvsViewModel對象在所有屬性中都有數據。

正在成功地分配數據UserFeatruesEvs類屬性只是具有由所指爲空的數據類型的人?在數據類型之後,如下面的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; } 

. 
. 
. 

我什麼都看不到,是造成這個問題,就像我前面說的,我已經使用這個與其他兩個數據庫表相同的實體類/視圖模型類技術沒有問題。

我在上面討論的所有代碼都在ASP.Net Core API項目中。

我試過刪除?從UserFeaturesEvs類屬性中的數據類型聲明中,當我這樣做時,調試器跳過了所有的屬性賦值,並從映射方法返回所有的空數據。

編輯:進一步的分析表明,問題是與UserFeaturesEvsViewModel。我可以靜態地將值分配給MapUserFeaturesEvsViewModelToUserFeaturesEvs方法中的UserFeaturesEvs對象實例,它不會跳過沒有的屬性分配?在他們的數據類型聲明之後。由於這是一個API,UserFeatruesEvsViewModel來自API控制器中的Create方法。

[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從谷歌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,我看到了API控制器的JSON的樣本我發佈的數據,它似乎在UserVeaturesEvsViewModel類的結構中。但是,當我嘗試在Create方法的開始處簡單地將a_vm變量的屬性分配給局部變量時,如上所示,這些分配也僅由調試器跳過(即使我在賦值上放置了斷點),就像MapUserFeaturesEvsViewModelToUserFeaturesEvs方法中發生的一樣。

在其他沒有此問題的API控制器中,我將a_vm對象傳遞到我的實體框架存儲庫中。例如,這個相同的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的身體在創建方法反序列化的方式來。儘管在調試器中,我看到了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

相關問題