5

Mam kontroler działający w usłudze aplikacji Azure - urządzenia mobilne. Śledzenie pokazuje, że poniższy kod działa poprawnie, aż do momentu, w którym db.SaveChanges() zakończy się niepowodzeniem.Kontekst Db na usłudze aplikacji usługi azure (telefonii komórkowej) kończy się niepowodzeniem

var telemetry = new Microsoft.ApplicationInsights.TelemetryClient(); 
telemetry.TrackTrace("Create User"); 
using (BCMobileAppContext db = new BCMobileAppContext()) 
{ 
    string Username_NoSpaces = username.Username.Replace(" ", ""); 
    var user = db.Users.FirstOrDefault(u => u.Username_NoSpaces == Username_NoSpaces || u.MicrosoftToken == this.User.Identity.Name); 
    telemetry.TrackTrace("1"); 
    if (user == null && !Username_NoSpaces.Contains(",")) 
    { 
      telemetry.TrackTrace("2"); 
      DateTime now = DateTime.UtcNow; 
      telemetry.TrackTrace("3"); 
      string username_noSpaces = username.Username.Replace(" ", ""); 
      DataObjects.User userItem = new DataObjects.User() { Created = now, UserId = this.User.Identity.Name, MicrosoftToken = this.User.Identity.Name, Username_NoSpaces = username_noSpaces, Update = now, Username = username.Username, Gold = 1, Level = 1, Title = "Sir", InGameCrest = "", ReceiveNotifications = true }; 
      telemetry.TrackTrace("4"); 
      UserDTO returnObject1 = new UserDTO() { Created = userItem.Created, isCreated = true, MicrosoftId = userItem.MicrosoftToken, Username = userItem.Username }; 
      telemetry.TrackTrace("5"); 
      db.Users.Add(userItem); 
      telemetry.TrackTrace("6"); 
      db.SaveChanges();   //Trace and code fails 
      telemetry.TrackTrace("7"); 
      UserDTO returnObject = new UserDTO() { Created = userItem.Created, isCreated = true, MicrosoftId = userItem.MicrosoftToken, Username = userItem.Username }; 
      telemetry.TrackTrace("8"); 
      return Ok(returnObject); 
     } 
} 

StackTrace z diagnostyki na appservice (które niestety nie rozumiem) daje:

2016-04-07T17:29:19 PID[5008] Error  Operation=ReflectedHttpActionDescriptor.ExecuteAsync, Exception=System.Data.Entity.Validation.DbEntityValidationException: Validation failed for one or more entities. See 'EntityValidationErrors' property for more details. 
    at System.Data.Entity.Internal.InternalContext.SaveChanges() 
    at System.Data.Entity.Internal.LazyInternalContext.SaveChanges() 
    at System.Data.Entity.DbContext.SaveChanges() 
    at BCMobileAppService.Controllers.Test2Controller.Post(UserDTO username) in C:\Users\johann\Desktop\BCMobileApp_Runtime\BCMobileAppService\Controllers\TestController.cs:line 78 
    at lambda_method(Closure , Object , Object[]) 
    at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters) 
    at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments) 
    at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary 2 arguments, CancellationToken cancellationToken) 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__18 1.MoveNext() 
2016-04-07T17:29:19 PID[5008] Error  Operation=ApiControllerActionInvoker.InvokeActionAsync, Exception=System.Data.Entity.Validation.DbEntityValidationException: Validation failed for one or more entities. See 'EntityValidationErrors' property for more details. 
    at System.Data.Entity.Internal.InternalContext.SaveChanges() 
    at System.Data.Entity.Internal.LazyInternalContext.SaveChanges() 
    at System.Data.Entity.DbContext.SaveChanges() 
    at BCMobileAppService.Controllers.Test2Controller.Post(UserDTO username) in C:\Users\johann\Desktop\BCMobileApp_Runtime\BCMobileAppService\Controllers\TestController.cs:line 78 
    at lambda_method(Closure , Object , Object[]) 
    at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters) 
    at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments) 
    at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary 2 arguments, CancellationToken cancellationToken) 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__18 1.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__18 1.MoveNext() 
2016-04-07T17:29:19 PID[5008] Error  Operation=Test2Controller.ExecuteAsync, Exception=System.Data.Entity.Validation.DbEntityValidationException: Validation failed for one or more entities. See 'EntityValidationErrors' property for more details. 
    at System.Data.Entity.Internal.InternalContext.SaveChanges() 
    at System.Data.Entity.Internal.LazyInternalContext.SaveChanges() 
    at System.Data.Entity.DbContext.SaveChanges() 
    at BCMobileAppService.Controllers.Test2Controller.Post(UserDTO username) in C:\Users\johann\Desktop\BCMobileApp_Runtime\BCMobileAppService\Controllers\TestController.cs:line 78 
    at lambda_method(Closure , Object , Object[]) 
    at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.< >c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters) 
    at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments) 
    at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary 2 arguments, CancellationToken cancellationToken) 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__18 1.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__18 1.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__0.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Tracing.Tracers.HttpControllerTracer.<ExecuteAsyncCore>d__5.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__18 1.MoveNext() 

Aktualizacja

więc będę się starał this, co spowoduje wyświetlenie bardziej szczegółowego komunikatu o błędzie:

catch (DbEntityValidationException dbEx) 
{ 
foreach (var validationErrors in dbEx.EntityValidationErrors) 
{ 
    foreach (var validationError in validationErrors.ValidationErrors) 
    { 
     Trace.TraceInformation("Property: {0} Error: {1}", 
           validationError.PropertyName, 
           validationError.ErrorMessage); 
    } 
} 
} 

także

będę przejść przez wszystkie ustawienia, aby upewnić się, że pole, które nie muszą być null jest null jak według this answer on stackoverflow.

Testowanie powyższy

Wyjątkiem ukrywa, że ​​wymagana jest Id Pole jest wyjątkiem.

Baza danych, z której korzystam, zawiera numer EntityData (opisany here on msdn), z którego pochodzi Id. Moje użycie w MobileService polegało na tym, że Id został utworzony, gdy wykonałem linię, która nie udała się db.SaveChanges(). Czy ktoś może to wyjaśnić? Klasa wygląda następująco:

public abstract class EntityData : ITableData 
{ 
    protected EntityData(); 

    [Index(IsClustered = true)] 
    [TableColumn(TableColumnType.CreatedAt)] 
    public DateTimeOffset? CreatedAt { get; set; } 
    [TableColumn(TableColumnType.Deleted)] 
    public bool Deleted { get; set; } 
    [TableColumn(TableColumnType.Id)] 
    public string Id { get; set; } 
    [TableColumn(TableColumnType.UpdatedAt)] 
    public DateTimeOffset? UpdatedAt { get; set; } 
    [TableColumn(TableColumnType.Version)] 
    public byte[] Version { get; set; } 
} 
+0

nadal masz błąd po przejściu przez ustawienia wspomniane powyżej? –

+0

@RamiSarieddine Teraz przetestowałem wszystko i napisałem aktualizację pytania, to jest pole 'Id' z' EntityData', które daje 'wyjątek'. Miałem zrozumienie z poprzedniej pracy, że to zostało stworzone, kiedy zrobiłem 'db.SaveChanges()', która jest linią, która zawodzi podczas wykonywania. Czy wiesz, dlaczego tak jest? Nie użyłem wcześniej 'EntityData', ale chciałbym to zrobić z powodu kolumn' CreatedAt' i 'UpdatedAt', które byłyby automatycznie aktualizowane? – JTIM

+0

@AlexanderDerck Nie, więc wnioskowanie od ciebie: Moja klasa dziedzicząca z 'EntityData' powinna mieć zmienną' [DatabaseGenerated (DatabaseGeneratedOption.Identity)] public string Id {get; set;} 'jako zgodny z typem z' EntityData', lub? – JTIM

Odpowiedz

3

Nie ma automatycznego generowania obsługę łańcucha klucza podstawowego w EF. Dlatego należy przypisać klucz podstawowy ręcznie.

Można zainicjować Id, CreatedDate i UpdatedDate z konstruktorem.

public abstract class EntityData : ITableData 
    { 
    //Change the constructor to initilaize required filled with meaningful data. 
     protected EntityData() 
     { 
      Id=Guid.NewGuid().ToString(); 
      CreatedDate=DateTime.UtcNow; 
      UpdatedDate=DateTime.UtcNow; 
     } 

     [Index(IsClustered = true)] 
     [TableColumn(TableColumnType.CreatedAt)] 
     public DateTimeOffset? CreatedAt { get; set; } 
     [TableColumn(TableColumnType.Deleted)] 
     public bool Deleted { get; set; } 
     [TableColumn(TableColumnType.Id)] 
     public string Id { get; set; } 
     [TableColumn(TableColumnType.UpdatedAt)] 
     public DateTimeOffset? UpdatedAt { get; set; } 
     [TableColumn(TableColumnType.Version)] 
     public byte[] Version { get; set; } 
    } 

Możesz zastąpić metodę zapisywania w swoim kontekście. Po zmodyfikowaniu obiektu ta metoda automatycznie zmieni aktualizację.

public override int SaveChanges() 
    { 
     //Get Modified Entities 
     var modifiedEntries = ChangeTracker.Entries() 
      .Where(x => x.Entity is ITableData 
       && (x.State == EntityState.EntityState.Modified)); 
     foreach (var entry in modifiedEntries) 
     { 
      var entity = entry.Entity as ITableData; 
      //Modify updateddate 
      if (entity != null) 
      { 
       entity.UpdatedDate = DateTime.UtcNow; 
      } 
     } 
     return base.SaveChanges(); 
    } 

Edit: Pierwsze rozwiązanie było ogólne rozwiązanie, które nie jest realeted z dowolnej biblioteki.

EntityData potrzebujesz do serilazacji. Kiedy klient mobilny i serwer zaplecza próbują się ze sobą komunikować, ta klasa pomoże. Przykładowy klient mobilny nie obsługuje właściwości nawigacji, ale działa serwer zaplecza. Kiedy serillaize entitydata, ukryje te właściwości dla ciebie.

Jeśli projektujesz bazę danych dla tej aplikacji. Postępuj zgodnie z document.

Po pierwsze: powinieneś użyć klasy EntityData, która znajduje się w bibliotece. Twoje modele powinny odziedziczyć nie klasę EntityData.

Po drugie: Twój kontekst powinien zawierać ten kod podczas tworzenia modelu zastępowania. Potrzebujesz tego do automatycznej aktualizacji utworzonego/zaktualizowanego at i Id (to jest odpowiedź na twoje pytanie).

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
     { 
      string schema = ServiceSettingsDictionary.GetSchemaName(); 
      if (!string.IsNullOrEmpty(schema)) 
      { 
       modelBuilder.HasDefaultSchema(schema); 
      } 

      modelBuilder.Conventions.Add(
       new AttributeToColumnAnnotationConvention<TableColumnAttribute, string>(
        "ServiceTableColumn", (property, attributes) => attributes.Single().ColumnType.ToString())); 
     } 

przypadku korzystania z bazy danych, która jest już istniejącej obserwować tą document.

+0

Dobra, więc normalną praktyką jest zastąpienie tej funkcji? Jeśli tak, gdzie w rozwiązaniu powinienem umieścić to w sterowniku lub? – JTIM

+1

W 'BCMobileAppContext' –

+0

OK, spróbuję tego dziś wieczorem! – JTIM

Powiązane problemy