2016-11-06 3 views
1

Я боролся с этой проблемой за последние пару дней. У меня есть веб-приложение, которое связывается с API WebAPI для извлечения и обновления объектов, которые создаются и поддерживаются с помощью расширения визуальной студии «Entity Framework Reverse POCO CodeFirst Generator». Кажется, что все они генерируют сущности и DbContext просто отлично. Но вот проблема: веб-клиент делает ajax-вызов API-методу, который возвращает объект «Пациент». У этой пациентской сущности есть пара нулевых внешних ключей, а именно LanguageId и PharmacyId. Теперь, когда Пациент извлекается репозиторием, он отлично выглядит на сервере Error screen shot 1. LanguageId и PharmacyId являются нулевыми, как ожидалось. Свойства навигации Patient, а именно luLanguage и Pharmacy, также по праву имеют значение null. Объект json, полученный клиентом, также отлично выглядит на данный момент Error Screen shot 2. И идентификаторы внешнего ключа, и свойства навигации являются нулевыми. Клиент выполняет некоторые дополнительные изменения для объекта пациента и отправляет объект обратно на сервер. Как раз перед тем, как выполняется POST-аякс-вызов, объект-клиент Patient по-прежнему выглядит нормально, как и ожидалось Error Screen shot 3. Внешние ключи и свойства навигации равны нулю. Но как только этот объект получен методом WebAPI, странно, есть пустые свойства навигации по языку и аптеке Error Screen shot 4. Первичные ключи, соответствующие внешним ключам, являются INT, они инициализируются 0. Это делает DbContext безумным, когда он пытается их обновить, поскольку внешний ключ для языка и первичный ключ в объекте навигации Language не совпадают. Один из них - null, а другой - 0 (ноль). Я пробовал так много разных тестов, но независимо от того, как я его разрезал, я возвращаюсь к той же проблеме.EF6, генерирующий пустой дочерний объект для обнуляемого внешнего ключа

Вот код конфигурации конструктора модели Entity.

public PatientConfiguration(string schema) 
    { 
     ToTable("Patient", schema); 
     HasKey(x => x.Id); 

     Property(x => x.Id).HasColumnName(@"ID").IsRequired().HasColumnType("bigint").HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity); 
     Property(x => x.LastName).HasColumnName(@"LastName").IsOptional().IsUnicode(false).HasColumnType("varchar").HasMaxLength(50); 
     Property(x => x.FirstName).HasColumnName(@"FirstName").IsOptional().IsUnicode(false).HasColumnType("varchar").HasMaxLength(50); 
     Property(x => x.MiddleName).HasColumnName(@"MiddleName").IsOptional().IsUnicode(false).HasColumnType("varchar").HasMaxLength(30); 
     Property(x => x.Gender).HasColumnName(@"Gender").IsOptional().IsUnicode(false).HasColumnType("varchar").HasMaxLength(18); 
     Property(x => x.Dob).HasColumnName(@"DOB").IsRequired().HasColumnType("datetime"); 
     Property(x => x.SocialSecurity).HasColumnName(@"SocialSecurity").IsOptional().HasColumnType("varbinary"); 
     Property(x => x.LastFourSsn).HasColumnName(@"LastFourSSN").IsOptional().HasColumnType("int"); 
     Property(x => x.PharmacyId).HasColumnName(@"PharmacyID").IsOptional().HasColumnType("bigint"); 
     Property(x => x.InUseById).HasColumnName(@"InUseByID").IsOptional().HasColumnType("bigint"); 
     Property(x => x.LanguageId).HasColumnName(@"LanguageID").IsOptional().HasColumnType("int"); 
     Property(x => x.Status).HasColumnName(@"Status").IsOptional().IsUnicode(false).HasColumnType("varchar").HasMaxLength(10); 
     Property(x => x.IsInactive).HasColumnName(@"IsInactive").IsRequired().HasColumnType("bit"); 
     Property(x => x.CreatedById).HasColumnName(@"CreatedByID").IsRequired().HasColumnType("bigint"); 
     Property(x => x.CreatedDate).HasColumnName(@"CreatedDate").IsRequired().HasColumnType("datetime"); 
     Property(x => x.UpdatedById).HasColumnName(@"UpdatedByID").IsRequired().HasColumnType("bigint"); 
     Property(x => x.UpdatedDate).HasColumnName(@"UpdatedDate").IsRequired().HasColumnType("datetime"); 
     Property(x => x.MigratedBy).HasColumnName(@"MigratedBy").IsOptional().IsUnicode(false).HasColumnType("varchar").HasMaxLength(10); 
     Property(x => x.TimeStamped).HasColumnName(@"TimeStamped").IsRequired().IsFixedLength().HasColumnType("timestamp").HasMaxLength(8).IsRowVersion().HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Computed); 

     // Foreign keys 
     HasOptional(a => a.LuLanguage).WithMany(b => b.Patients).HasForeignKey(c => c.LanguageId).WillCascadeOnDelete(false); // FK_Patient_luLanguage 
     HasOptional(a => a.Pharmacy).WithMany(b => b.Patients).HasForeignKey(c => c.PharmacyId).WillCascadeOnDelete(false); // FK_Pharmacy_Patient 
     InitializePartial(); 
    } 

А вот сгенерированный Entity пациента

public partial class Patient : EntityBase 
{ 
    //[DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public long Id { get; set; } // ID (Primary key) 
    public string LastName { get; set; } // LastName (length: 50) 
    public string FirstName { get; set; } // FirstName (length: 50) 
    public string MiddleName { get; set; } // MiddleName (length: 30) 
    public string Gender { get; set; } // Gender (length: 18) 
    public System.DateTime Dob { get; set; } // DOB 
    public byte[] SocialSecurity { get; set; } // SocialSecurity 
    public int? LastFourSsn { get; set; } // LastFourSSN 
    public long? PharmacyId { get; set; } // PharmacyID 
    public long? InUseById { get; set; } // InUseByID 
    public int? LanguageId { get; set; } // LanguageID 
    public string Status { get; set; } // Status (length: 10) 
    public bool IsInactive { get; set; } // IsInactive 
    public long CreatedById { get; set; } // CreatedByID 
    public System.DateTime CreatedDate { get; set; } // CreatedDate 
    public long UpdatedById { get; set; } // UpdatedByID 
    public System.DateTime UpdatedDate { get; set; } // UpdatedDate 
    public string MigratedBy { get; set; } // MigratedBy (length: 10) 
    public byte[] TimeStamped { get; private set; } // TimeStamped (length: 8) 

    // Reverse navigation 
    public virtual System.Collections.Generic.ICollection<AuditPatientChange> AuditPatientChanges { get; set; } // auditPatientChange.R_88 
    public virtual System.Collections.Generic.ICollection<PatientAddress> PatientAddresses { get; set; } // PatientAddress.FK_PatientAddress_Patient 
    public virtual System.Collections.Generic.ICollection<PatientCallTracking> PatientCallTrackings { get; set; } // PatientCallTracking.R_74 
    public virtual System.Collections.Generic.ICollection<PatientContact> PatientContacts { get; set; } // PatientContact.FK_PatientContact_Patient 
    public virtual System.Collections.Generic.ICollection<PatientCreditCard> PatientCreditCards { get; set; } // PatientCreditCard.R_59 
    public virtual System.Collections.Generic.ICollection<PatientDiseaseState> PatientDiseaseStates { get; set; } // PatientDiseaseState.R_65 
    public virtual System.Collections.Generic.ICollection<PatientIcd10> PatientIcd10 { get; set; } // PatientICD10.R_63 
    public virtual System.Collections.Generic.ICollection<PatientMedicalHistory> PatientMedicalHistories { get; set; } // PatientMedicalHistory.R_60 
    public virtual System.Collections.Generic.ICollection<PatientNoteAndComment> PatientNoteAndComments { get; set; } // PatientNoteAndComment.R_73 
    public virtual System.Collections.Generic.ICollection<PatientPayment> PatientPayments { get; set; } // PatientPayment.R_56 
    public virtual System.Collections.Generic.ICollection<PatientPlanPolicy> PatientPlanPolicies { get; set; } // PatientPlanPolicy.R_90 
    public virtual System.Collections.Generic.ICollection<PatientReferral> PatientReferrals { get; set; } // PatientReferral.FK_PatientReferral_Patient 
    public virtual System.Collections.Generic.ICollection<PatientShareOfCost> PatientShareOfCosts { get; set; } // PatientShareOfCost.R_62 
    public virtual System.Collections.Generic.ICollection<Rx> Rxes { get; set; } // Rx.FK_Rx_Patient 

    // Foreign keys 
    public virtual LuLanguage LuLanguage { get; set; } // FK_Patient_luLanguage 
    public virtual Pharmacy Pharmacy { get; set; } // FK_Pharmacy_Patient 

    public Patient() 
    { 
     IsInactive = false; 
     CreatedById = 0; 
     UpdatedById = 0; 
     AuditPatientChanges = new System.Collections.Generic.List<AuditPatientChange>(); 
     PatientAddresses = new System.Collections.Generic.List<PatientAddress>(); 
     PatientCallTrackings = new System.Collections.Generic.List<PatientCallTracking>(); 
     PatientContacts = new System.Collections.Generic.List<PatientContact>(); 
     PatientCreditCards = new System.Collections.Generic.List<PatientCreditCard>(); 
     PatientDiseaseStates = new System.Collections.Generic.List<PatientDiseaseState>(); 
     PatientIcd10 = new System.Collections.Generic.List<PatientIcd10>(); 
     PatientMedicalHistories = new System.Collections.Generic.List<PatientMedicalHistory>(); 
     PatientNoteAndComments = new System.Collections.Generic.List<PatientNoteAndComment>(); 
     PatientPayments = new System.Collections.Generic.List<PatientPayment>(); 
     PatientPlanPolicies = new System.Collections.Generic.List<PatientPlanPolicy>(); 
     PatientReferrals = new System.Collections.Generic.List<PatientReferral>(); 
     PatientShareOfCosts = new System.Collections.Generic.List<PatientShareOfCost>(); 
     Rxes = new System.Collections.Generic.List<Rx>(); 
     InitializePartial(); 
    } 

    partial void InitializePartial(); 
} 

и здесь на стороне клиента Javascript код, чтобы проверить эту проблему:

function testx1(){ 

var patient; 

$.ajax({ 
    type: 'GET', 
    url: "/api/patient/patient/61143", 
    success: function (result) { 
     patient = result; 
     testx2(patient); 
    }, 
    error: function (xhr, options, error) { 
     debugger; 
     alert(error); 
    } 
}); 
} 

function testx2(patient) { 
    patient.LastFourSsn = 5555; 
    patient.ObjectStateEnum = 2; 
    var x = "adsf"; 
    $.ajax({ 
     type: 'POST', 
     url: "/api/patient/patient", 
     data: patient, 
     dataType: "json", 
     success: function (result) { 
     }, 
     error: function (xhr, options, error) { 
     } 
    }); 
} 

Мой WebAPI код:

 [Route("patient/{id}")] 
    [HttpGet] 
    public async Task<IHttpActionResult> GetPatientByIdAsync(long id) 
    { 
     try 
     { 
      var patient = await patientService.GetPatientByIdAsync(id); 
      if (patient == null) 
       return NotFound(); 
      return Ok(patient); 
     } 
     catch (Exception ex) 
     { 
      return InternalServerError(); 
     } 
    } 

    [Route("patient")] 
    [HttpPost] 
    public async Task<IHttpActionResult> SavePatient(Patient patient) 
    { 
     try 
     { 
      //if (patient.LanguageId == null && patient.LuLanguage?.Id == 0) 
      // patient.LuLanguage = null; 
      //if (patient.PharmacyId == null && patient.Pharmacy?.Id == 0) 
      // patient.Pharmacy = null; 
      IOperationStatus result = await patientService.UpdateAndSavePatientAsync(patient); 
      if (!result.Success) 
       return InternalServerError(new Exception(result.Message)); 
      else 
       return Ok(); 
     } 
     catch (Exception ex) 
     { 
      return InternalServerError(ex); 
     } 
    } 
} 

Это мой Настройки сериализатора Json:

public class BrowserJsonFormatter : JsonMediaTypeFormatter 
{ 
    public BrowserJsonFormatter() 
    { 
     this.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html")); 
     this.SerializerSettings.Formatting = Formatting.Indented; 
    } 

    public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType) 
    { 
     base.SetDefaultContentHeaders(type, headers, mediaType); 
     headers.ContentType = new MediaTypeHeaderValue("application/json"); 
    } 
} 
+0

Не могли бы вы также указать свой фактический код метода webapi? –

+0

@Wiktor: Я редактировал свое сообщение, чтобы включить код методов WebAPI. Благодарю. –

+0

Итак, когда вы вызываете 'SavePatient', связанный параметр' patient' уже имеет неправильные значения (0 вместо null)? –

ответ

0

Мне пришлось внести пару изменений в мою проблему, чтобы решить проблему. Во-первых, мне пришлось сделать JSON.stringify на моем объекте json, который должен был быть отправлен обратно на сервер для обновления, а также конкретно упоминать «contentType:« application/json »в сообщении ajax. Во-вторых, мне пришлось пойти с VS, встроенным в ADO.NET Entity Data Model, для генерации моего DbContext вместо использования Entity Framework Reverse POCO Generator. С этими изменениями все стало работать.Я уверен, что если я углубится в код dbContext, сгенерированный этими двумя инструментами, я могу найти причину, по которой мой индекс timestamp (rowversion) не получил должным образом мой метод WebAPI. Но так как я был в хрусте времени, мне пришлось отложить расследование еще на один день. Сейчас это работает, и все это, по крайней мере, сейчас. Спасибо всем за помощь.

EDIT: На всякий случай другие сталкиваются с одной и той же проблемой, вот что я узнал после двух мучительных дней, пытаясь решить эту проблему. Оказывается, что «Entity Framework Reverse POCO Generator» создает свойство rowversion с помощью {get; частный комплект} и правильно поэтому. Но когда метод WebAPI получает запрос POST, этот процесс не может, по-видимому, генерировать класс Entity из json и устанавливать столбец timestamp со значением. Итак, я отредактировал файл .tt, чтобы дать столбцу timestamp открытый доступ и установить {get; set;}. Это устранило все мои проблемы. Мне все равно понравился частный сеттер для столбца rowversion (timestamp) и каким-то образом установил значение. Но из-за временного кризиса я просто соглашусь на это решение.

0

Я считаю, что ваша проблема связана с тем, как вы сериализуете объект.

Чтобы это подтвердить, вручную добавьте свойства Language и LanguageLu в POST.

function testx2(patient) { 
patient.LastFourSsn = 5555; 
patient.ObjectStateEnum = 2; 
patient.LuLanguage = null; 
patient.Language = null; 
var x = "adsf"; 
$.ajax({ 
    type: 'POST', 
    url: "/api/patient/patient", 
    data: patient, 
    dataType: "json", 
    success: function (result) { 
    }, 
    error: function (xhr, options, error) { 
    } 
}); 

}

Если это работает нормально, то мы можем быть вполне уверены в том, что существует проблема с сериализации объекта пациента, и вы должны разместить код для сериализатором JSON, который вы используете.

Else Я бы посмотрел дальше на свободный API-синтаксис.

+0

Спасибо. Я редактировал свой пост, чтобы показать настройки сериализации. Что касается вашего ответа, то пациент.LuLanguage уже имеет значение null, когда получена javascript функцией testx2 (пациент). Итак, я бы предположил, что мне не нужно устанавливать его вручную. Даже если это работает, я не хочу идти по этому маршруту, потому что у меня есть более 100 объектов, используемых клиентом таким способом, как это. Кроме того, многие из них имеют глубоко вложенные навигационные свойства. Было бы контрпродуктивно устанавливать их вручную на клиенте. Поэтому мне нужно найти лучшее решение/подход. –

+0

@BabuMannavalappil Это предназначено только для диагностических целей. Похоже, что сериализатор Json (de) инициализирует объекты по умолчанию. –

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