Sto riscontrando un problema nell'aggiunta di una nuova entità tramite il metodo DbContext.Add (...). Su DbContext.SaveChanges (), ottengo DbUpdateConcurrencyException. Sto cercando di inserire un inserto nel database. Sono l'unico sviluppatore dell'applicazione, che esegue localhost e la tabella del database è incontaminata. Non ci sono utenti. Sono solo io.
Questo non ha aiutato, anche se è simile:
Entity Framework 6 DbUpdateConcurrencyException quando si aggiungono nuove righe al database
Sto usando un DbContext per richiesta. Come questo:
Un DbContext per richiesta in ASP.NET MVC (senza contenitore IOC)
Sto disconnettendo l'istruzione sql generata dalla struttura dell'entità in questo modo:
https://stackoverflow.com/a/20751723/2088914
Ecco il modello (prima il codice, con le migrazioni). Quando pubblico, fornisco solo l'associato, il ruolo, l'assegnatario e il flag cancellato. L'ID della riga viene automaticamente impostato su 0 poiché non lo fornisco dal client, e la data è anch'essa un valore predefinito, che poi compilo sul server: tutte le cose attese:
public class Permission {
[Column("row_id")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int RowId { get; set; }
[Key]
[StringLength(10)]
[Column("associate_nt_id", Order = 0)]
[Required]
public string AssociateNtId { get; set; }
[Key]
[Column("role_name", Order = 1)]
[StringLength(50)]
[Required]
public string RoleName { get; set; }
[Key]
[Column("eff_ts", Order = 2)]
[Required]
public DateTime EffectiveTimestamp { get; set; }
[StringLength(10)]
[Column("assignor_nt_id")]
[Required]
public string RoleAssignorNtId { get; set; }
[Column("deleted")]
[Required]
public bool Deleted { get; set; }
}
Ho un controller web API con un metodo post, a cui si accede con successo da una spa angolare, e il modello viene popolato:
[HttpPost]
[Route("")]
[Require(Roles.admin)]
public Permission Post(Permission permission) {
permission.EffectiveTimestamp = DateTime.Now;
MAPDB.Current.Permissions.Add(permission);
MAPDB.Current.Database.Log = s => {
Debug.WriteLine(s);
};
MAPDB.Current.SaveChanges();
return permission;
}
Eseguo il debug in Visual Studio 2015. Ecco il messaggio di errore:
Ecco lo sql che il framework di entità sta generando:
INSERT [dbo].[_permissions]([associate_nt_id], [role_name], [eff_ts], [assignor_nt_id], [deleted])
VALUES (@0, @1, @2, @3, @4)
SELECT [row_id]
FROM [dbo].[_permissions]
WHERE @@ROWCOUNT > 0 AND [associate_nt_id] = @0 AND [role_name] = @1 AND [eff_ts] = @2
-- @0: 'associate' (Type = String, Size = 10)
-- @1: 'user' (Type = String, Size = 50)
-- @2: '9/20/2017 12:49:05 PM' (Type = DateTime2)
-- @3: 'assignor' (Type = String, Size = 10)
-- @4: 'True' (Type = Boolean)
-- Executing at 9/20/2017 12:49:05 PM -05:00
-- Completed in 24 ms with result: SqlDataReade
-- Closed connection at 9/20/2017 12:49:05 PM -05:00
Sembra che sia stato eseguito nel logger e l'affermazione è esattamente ciò che mi aspetterei, tranne che non si verifica alcun inserimento di database. Se estraggo la dichiarazione dal logger, compilo i parametri ed eseguo tramite un client sql, funziona e restituisce l'id di riga di ciò che è stato creato. Non capisco quale sia il problema - non si verifica alcuna situazione di concorrenza, nessuna colonna mancante / aggiunta quando non dovrebbe essere, nessun parametro non valido, nessun problema nel mappare le colonne alle proprietà dell'oggetto, nessuna violazione delle chiavi, nessun problema con la colonna Identity .
Come posso ottenere il framework entità per inserire semplicemente questo nuovo oggetto (senza ingoiare l'eccezione)?
Grazie per l'aiuto.
Molto probabilmente il problema è causato dalla parte DateTime
del PK ( EffectiveTimestamp
). Il record viene inserito, ma il SELECT
non lo trova, poiché l'EF associa le proprietà DateTime
alle colonne datetime , mentre come si può vedere dal log, il tipo di parametro è datetime2 , che ha una precisione maggiore, quindi viene troncato se memorizzato nella colonna della tabella, quindi non corrisponde alla [eff_ts] = @2
parte del filtro di selezione.
Per vedere se questo è il caso, puoi provare a ritagliare il valore temporale:
// ...
var time = DateTime.Now;
permission.EffectiveTimestamp = new DateTime(time.Year, time.Month, time.Day, time.Hour, time.Minute, time.Second);
// ...
Se funziona (come mi aspetto), potresti prendere in considerazione la modifica del tipo di colonna del database:
[Key]
[Column("eff_ts", Order = 2, TypeName="datetime2")]
[Required]
public DateTime EffectiveTimestamp { get; set; }