Entity Framework: "La declaración de actualización, inserción o eliminación de la tienda afectó un número inesperado de filas (0)". [cerrado]

324

Estoy usando Entity Framework para llenar un control de cuadrícula. A veces, cuando hago actualizaciones me sale el siguiente error:

La declaración de actualización, inserción o eliminación del almacén afectó un número inesperado de filas (0). Las entidades pueden haber sido modificadas o eliminadas desde que se cargaron las entidades. Actualizar entradas de ObjectStateManager.

No puedo entender cómo reproducir esto. Pero podría tener algo que ver con cuán juntas realizo las actualizaciones. ¿Alguien ha visto esto o alguien sabe a qué se refiere el mensaje de error?

Editar: Desafortunadamente, ya no tengo libertad para reproducir el problema que estaba teniendo aquí, porque me alejé de este proyecto y no recuerdo si finalmente encontré una solución, si otro desarrollador la arregló o si lo solucioné. Por lo tanto, no puedo aceptar ninguna respuesta.

fuertes opiniones
fuente
Obtuve este error con la introducción de una política de seguridad de nivel de fila de SQL Server que permitía actualizaciones a una fila en un estado que no se podía volver a leer (un predicado exclusivo de FILTER con un predicado de BLOCK permisivo) . EntityFramework requiere que la fila actualizada se lea de nuevo después de la actualización; de lo contrario, se supone que fue un error de concurrencia (al menos cuando se usa la concurrencia optimista).
xr280xr
El problema podría ser un alcance incorrecto para su DBContext stackoverflow.com/questions/49154250/… (este ejemplo es para la identidad ASPNET pero se aplica a cualquier contexto)
Simon_Weaver
Independientemente del contexto de este error, es una buena idea poner un punto de interrupción donde sea que se esté instanciando el contexto. ¿Esperaba que se instanciara una vez cuando cargó una página web pero está llegando a ese punto de interrupción 5 veces? Entonces probablemente tengas una condición de carrera. Mire Request.Uripara ver la URL de solicitud real. En mi caso, tenía cierta lógica de seguimiento que estaba afectando mi sitio y cargando innecesariamente el contexto desde el DB (y ocasionalmente actualizándolo también). Entonces, a la página real que estaba depurando se le había pisoteado la información con una estúpida lógica de código de seguimiento.
Simon_Weaver
agregar @ Html.AntiForgeryToken () a la vista
Vikas Sharma

Respuestas:

199

Ese es un efecto secundario de una característica llamada concurrencia optimista.

No estoy 100% seguro de cómo activarlo / desactivarlo en Entity Framework, pero básicamente lo que te dice es que entre cuando tomaste los datos de la base de datos y cuando guardaste los cambios, otra persona cambió los datos (lo que significaba cuando fuiste para guardarlo 0 filas realmente se actualizaron). En términos de SQL, updatela wherecláusula de su consulta contiene el valor original de cada campo en la fila, y si se ven afectadas 0 filas, sabe que algo salió mal.

La idea detrás de esto es que no terminará sobrescribiendo un cambio que su aplicación no sabía que sucedió; es básicamente una pequeña medida de seguridad incorporada por .NET en todas sus actualizaciones.

Si es coherente, es probable que esté sucediendo dentro de su propia lógica (por ejemplo: en realidad está actualizando los datos usted mismo en otro método entre la selección y la actualización), pero podría ser simplemente una condición de carrera entre dos aplicaciones.

Fyjham
fuente
34
Esto está sucediendo en un entorno de usuario único (en mi máquina de desarrollo), así que no creo que pueda ser una condición de carrera. Estoy vinculado a un control de cuadrícula personalizado con un EntityDataSource, así que no estoy seguro exactamente de lo que está sucediendo detrás de escena, pero no tengo ningún código adicional que esté modificando las tablas. ¿Hay alguna manera de cambiar esta configuración de concurrencia?
stronggopinions
3
Creo que puede hacerlo por columna en su modelo de entidad (está en la ventana de propiedades), pero la cuestión es que solo evitará que vea el error y aún no actualizará nada. ¿Puede ver los comandos SQL que van a su base de datos (por ejemplo, SQL Server Profiler para MSSQL)? De esta manera, podría ver qué actualización se genera y debería poder ver por qué esa actualización no afecta a ninguna fila.
fyjham
99
Si la entidad tiene una propiedad de marca de tiempo, asegúrese de tenerla almacenada en su vista y asegúrese de que la entidad llene la marca de tiempo correctamente.
anIBMer
Tenía una columna de marca de tiempo y una vez que la abordé, EF6.1 funcionó como se esperaba, gracias por el consejo @anelBMer
JQII
3
Si usa marcas de tiempo, el objeto tje que desea eliminar necesita el conjunto PK y la propiedad RowVersion para poder actualizarlo correctamente. Estaba configurando la propiedad rowVersion (marca de tiempo), después de haber adjuntado el objeto al DbSet respectivo, por eso no funcionó. ¡Buen trabajo!
Legends
394

Me encontré con esto y fue causado por el campo ID (clave) de la entidad que no se establece. Por lo tanto, cuando el contexto fue para guardar los datos, no pudo encontrar una ID = 0. Asegúrese de colocar un punto de interrupción en su declaración de actualización y verifique que se haya establecido la ID de la entidad.

Del comentario de Paul Bellora

Tuve este problema exacto, causado por olvidar incluir la entrada de ID oculta en la página de edición .cshtml

webtrifusion
fuente
3
+1 Estaba teniendo el mismo problema y esto ayudó a encontrar la solución. Resulta que tenía [Bind (Exclude = "OrderID")] en mi modelo de pedido que causaba que el valor de la ID de la entidad fuera cero en HttpPost.
Dhaust
2
Eso es exactamente lo que me faltaba. La identificación de mi objeto era 0.
Azhar Khorasany
44
@ Html.HiddenFor (model => model.productID): funcionó perfectamente. Me faltaba el ID de producto en la PÁGINA DE EDICIÓN (MVC RAZOR)
Ravi Ram
2
Tuve un problema similar pero con un giro. Para mí, el problema era que no tenía la configuración de la tabla SQL correctamente. Mi campo de clave principal no estaba configurado en incremento automático. Entonces, EF enviaría el registro que estaba tratando de insertar sin una clave, lo cual está bien si recuerdas decirle a sql que el campo es un campo de identidad de incremento automático, que olvidé: <
Agile Noob
1
Mismo problema pero usando una clave compuesta. No se estableció uno de los valores clave.
obaylis
113

Wow, muchas respuestas, pero recibí este error cuando hice algo ligeramente diferente que nadie más ha mencionado.

En pocas palabras, si crea un nuevo objeto y le dice a EF que se modificó usando el EntityState.Modified, arrojará este error ya que aún no existe en la base de datos. Aquí está mi código:

MyObject foo = new MyObject()
{
    someAttribute = someValue
};

context.Entry(foo).State = EntityState.Modified;
context.SaveChanges();

Sí, esto parece una tontería, pero surgió porque el método en cuestión solía foohaberse creado antes, ahora solo se lo ha someValuepasado y creafoo sí mismo.

Fijar fácil, simplemente el cambio EntityState.Modifiedde EntityState.Addedo cambio que toda la línea a:

context.MyObject.Add(foo);
Ben
fuente
Gracias por publicar esto. Ese también era mi problema, había pegado un código que estaba configurando el estado en EntityState.Modified.
clayRay
23

Estaba enfrentando este mismo error aterrador ... :) Entonces me di cuenta de que me estaba olvidando de establecer un

@Html.HiddenFor(model => model.UserProfile.UserId)

para la clave principal del objeto que se actualiza! ¡Tiendo a olvidar esta cosita simple pero muy importante!

Por cierto: HiddenFores para ASP.NET MVC.

Leniel Maccaferri
fuente
3
Eso parece una falla de seguridad, para almacenar UserIden el formulario, muy propenso a los piratas informáticos ... esto debe rellenarse después deHttpContext.Current.User.Identity.Name
Serj Sagan
@SerjSagan tiene razón ... pero siempre que realice algunas verificaciones en el lado del servidor para confirmar el UserId y el nombre de usuario actual, estará listo.
Leniel Maccaferri
1
Mi punto es por qué incluso almacenar eso en el HiddenForque necesitará obtenerlo de HttpContexttodos modos ... No pondría esta propiedad en el formulario, lo que me obligaría a poblarlo siempre en el lado del servidor ...
Serj Sagan
16

Compruebe si olvidó el atributo "DataKeyNames" en GridView. es imprescindible al modificar datos dentro de GridView

http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.datakeynames.aspx

Solly
fuente
+1. Solución perfecta y simple para mí. Estoy vinculando GridView a EntityDataSource y no configuré esto en mi clave principal en el objeto.
Andez
Sabemos que Kendo UI no admite claves compuestas, pero en caso de que agregue una nueva columna que concatene mis claves con una, ¿qué está sucediendo entonces?
Branislav
15

El problema es causado por una de dos cosas: -

  1. Intentó actualizar una fila con una o más propiedades son Concurrency Mode: Fixed... y la Concurrencia optimista evitó que se guardaran los datos. Es decir. algunos cambiaron los datos de la fila entre el momento en que recibió los datos del servidor y cuando guardó los datos del servidor.
  2. Intentó actualizar o eliminar una fila pero la fila no existe. Otro ejemplo de alguien cambiando los datos (en este caso, eliminando) entre una recuperación y luego guardar O está tratando de actualizar un campo que no es una Identidad (es decir StoreGeneratedPattern = Computed) y esa fila no existe.
Pure.Krome
fuente
1
Esto también podría ser causado si todas las propiedades de objeto que fueron asignadas, se les asignaron los mismos valores que tenían antes.
Serj Sagan
+1 para el segundo. Tenía StoreGeneratedPattern = None, cambiando a StoreGeneratedPattern = Identity resolvió el problema. Gracias
tkt986
12

Obtuve este mismo error porque parte de la PK era una columna de fecha y hora, y el registro que se insertaba usa DateTime.Now como el valor para esa columna. El marco de la entidad insertaría el valor con una precisión de milisegundos y luego buscaría el valor que acaba de insertar también con una precisión de milisegundos. Sin embargo, SqlServer había redondeado el valor a una segunda precisión y, por lo tanto, el marco de la entidad no pudo encontrar el valor de precisión de milisegundos.

La solución fue truncar los milisegundos de DateTime.Now antes de insertar.

innominado227
fuente
2
Tuvimos el mismo problema, excepto que estábamos insertando en una Datecolumna con un DateTimevalor
adam0101 el
1
Igual que aquí. Teníamos un registro de almacén de datos y estábamos usando la marca de tiempo como parte de la clave. La marca de tiempo en el almacén de datos era un SQL DateTime, pero la marca de tiempo en C # no coincidía. Cambié el tipo de datos SQL a DateTime2 (7), actualicé el modelo EF y todo se solucionó.
mmcfly
Cambiar la columna a Datetime2 (7) también funcionó para mí. Gracias @mmcfly
Dzejms
10

Estaba teniendo el mismo problema y la respuesta de @ webtrifusion ayudó a encontrar la solución.

Mi modelo estaba usando el Bind(Exclude)atributo en la ID de la entidad, lo que causaba que el valor de la ID de la entidad fuera cero en HttpPost.

namespace OrderUp.Models
{
[Bind(Exclude = "OrderID")]
public class Order
{
    [ScaffoldColumn(false)]
    public int OrderID { get; set; }

    [ScaffoldColumn(false)]
    public System.DateTime OrderDate { get; set; }

    [Required(ErrorMessage = "Name is required")]
    public string Username { get; set; }
    }
}   
Dhaust
fuente
Problema similar, por razones de seguridad, tengo Bind (include = some fields). La identificación no estaba en la lista. También lo agregué como una entrada oculta. Debe haber borrado algo generado por MVC o la identificación no estaba allí en absoluto. Gracias por la ayuda.
MusicAndCode
10

Tuve el mismo problema, descubrí que fue causado por RowVersion, que era nulo. Verifique que su ID y su RowVersion no sean nulos .

Para obtener más información, consulte este tutorial

http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/handling-concurrency-with-the-entity-framework-in-an-asp-net-mvc-application

Bilel Chaouadi
fuente
la versión de la fila era nula en mi caso
Prakash
En mi caso, eliminé accidentalmente el campo Id en mi [Bind (Incluir = propiedades)]. Agréguelo de nuevo y funcionó bien.
Caverman
8

Comencé a recibir este error después de cambiar de modelo primero a código primero. Tengo varios subprocesos que actualizan una base de datos donde algunos podrían actualizar la misma fila. No sé por qué no tuve problemas al usar model-first, supongamos que usa un valor predeterminado de concurrencia diferente.

Para manejarlo en un lugar sabiendo las condiciones bajo las cuales podría ocurrir, agregué la siguiente sobrecarga a mi clase DbContext:

using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;

public class MyDbContext: DbContext {
...
        public int SaveChanges(bool refreshOnConcurrencyException, RefreshMode refreshMode = RefreshMode.ClientWins) {
            try {
                return SaveChanges();
            }
            catch (DbUpdateConcurrencyException ex) {
                foreach (DbEntityEntry entry in ex.Entries) {
                    if (refreshMode == RefreshMode.ClientWins)
                        entry.OriginalValues.SetValues(entry.GetDatabaseValues());
                    else
                        entry.Reload();
                }
                return SaveChanges();
            }
        }
}

Luego se llama SaveChanges(true)cuando corresponda.

avenmore
fuente
1
De acuerdo, todos los demás se quejan del problema, muestran cómo pueden desencadenarlo, etc., pero esta respuesta tiene una respuesta genial. Utilizo un modelo de actualización continua (no hay botón de guardar aquí, bebé) y estaba obteniendo esto en las actualizaciones de la cuadrícula cuando el hilo EF se estaba quedando atrás, y lo resolvió. Brillante trabajo, mi buen nombre ... ¡me hiciste parecer un héroe, de pie en el hombro de gigantes!
Tony Trembath-Drake
También me ayudó, mire esto para obtener más opciones- stackoverflow.com/a/13891724/4836581
Zvi Redler
7

Debe incluir explícitamente un BoundField de la clave primaria. Si no desea que el usuario vea la clave principal, debe ocultarla mediante css:

    <asp:BoundField DataField="Id_primary_key" ItemStyle-CssClass="hidden" 
HeaderStyle-CssClass="hidden" />

Donde 'oculto' es una clase en css que tiene su pantalla configurada en 'ninguna'.

Paulo
fuente
1
ja, me indicaste el hecho de que eliminé mi campo de identificación oculto en ASP.NET MVC. Gracias @Paulo! :)
Tomasz Iniewicz
7

Mientras edita, incluya la identificación o la clave principal de la entidad como un campo oculto en la vista

es decir

      @Html.HiddenFor(m => m.Id)

Eso resuelve el problema.

Además, si su modelo incluye un elemento no utilizado, inclúyalo también y publíquelo en el controlador

Arun Aravind
fuente
7

También me encontré con este error. El problema resultó que fue causado por un Trigger en la mesa en la que intentaba guardar. El activador usó 'INSTEAD OF INSERT', lo que significa que 0 filas alguna vez se insertaron en esa tabla, de ahí el error. Afortunadamente, en muchos casos, la funcionalidad del disparador era incorrecta, pero supongo que podría ser una operación válida que de alguna manera debería manejarse en código. Espero que esto ayude a alguien algún día.

Pecado
fuente
2
Se puede engañar a la entidad para que crea que se agregaron filas al devolver una instrucción SELECT (con la columna de clave principal) desde el disparador.
jahu
1
Para ampliar el comentario de @jahu, tuve que obtener una identificación real del elemento recién insertado para que sea devuelto por mi activador y el nombre de la columna debe coincidir con la columna de identidad de la tabla de activadores (en mi caso, en realidad una vista, por lo que no No tengo una identidad propia, pero había engañado a la EDMX para que creyera que sí). Mi gatillo estaba haciendo una inserción en una tabla separada, así que acabo de agregar esta última línea a mi gatillo:SELECT SCOPE_IDENTITY() as MyViewId
DannyMeister
También vea esta pregunta: stackoverflow.com/questions/5820992/…
J. Polfer
En mi caso, estaba haciendo una operación de eliminación en entidades en una colección secundaria, pero hubo un desencadenante en la eliminación de una de las entidades secundarias que causó que se eliminara otra de las entidades secundarias. Esto causó el error ya que las filas N - 1 se vieron afectadas debido a que el disparador eliminó una de las entidades secundarias antes de que el marco de la entidad intentara eliminarla.
skeletank
6

Me encontré con este problema en una tabla a la que le faltaba una clave principal y tenía una columna DATETIME (2, 3) (por lo que la "clave principal" de la entidad era una combinación de todas las columnas) ... Al realizar la inserción, la marca de tiempo tenía un tiempo más preciso (2018-03-20 08: 29: 51.8319154) que se truncó a (2018-03-20 08: 29: 51.832) por lo que la búsqueda en los campos clave falla.

combatc2
fuente
5

También tuve este error. Hay algunas situaciones en las que la Entidad puede no conocer el Contexto de base de datos real que está utilizando o el Modelo puede ser diferente. Para esto, establezca: EntityState.Modified; a EntityState.Added;

Para hacer esto:

if (ModelState.IsValid)
{
context.Entry(yourModelReference).State = EntityState.Added;
context.SaveChanges();
}

Esto asegurará que la Entidad sepa que está utilizando o agregando el Estado con el que está trabajando. En este punto, se deben establecer todos los valores de modelo correctos. Tenga cuidado de no perder ningún cambio que pueda haberse realizado en segundo plano.

Espero que esto ayude.

clavo oxidado
fuente
1
eres un gurú! ¡funciona para mí!
Hernaldo González
5
  @Html.HiddenFor(model => model.RowVersion)

Mi versión de fila era nula, así que tuve que agregar esto a la vista que resolvió mi problema

Prakash
fuente
No pasaba la RowVersion de la Vista a la Acción de edición, además, olvidé hacer el enlace del modelo para RowVersion. En el momento en que guarda el objeto en db, necesita el valor anterior del envío de RowVersion a la base de datos junto con el objeto para la verificación de concurrencia. ¡Cometes errores tontos cuando necesitas cosas más rápido!
Dhanuka777
5

La línea [DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.None)]hizo el truco en mi caso:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;


[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int? SomeNumber { get; set; }
Tomo
fuente
4

Solo asegúrese de que la tabla y el formulario tengan la clave principal y edmx actualizadas.

descubrí que cualquier error durante la actualización generalmente se debía a: - No hay clave principal en la Tabla - No hay clave principal en la vista / formulario Editar (por ejemplo @Html.HiddenFor(m=>m.Id)

Moji
fuente
4

Yo tuve el mismo problema. En mi caso, estaba tratando de actualizar la clave primaria, que no está permitida.

ajaysinghdav10d
fuente
4

Recibí este error esporádicamente cuando uso un asyncmétodo. No ha sucedido desde que cambié a un método sincrónico.

Errores esporádicos:

[Authorize(Roles = "Admin")]
[HttpDelete]
[Route("file/{id}/{customerId}/")]
public async Task<IHttpActionResult> Delete(int id, int customerId)
{
    var file = new Models.File() { Id = id, CustomerId = customerId };
    db.Files.Attach(file);
    db.Files.Remove(file);

    await db.SaveChangesAsync();

    return Ok();
}

Funciona todo el tiempo:

[Authorize(Roles = "Admin")]
[HttpDelete]
[Route("file/{id}/{customerId}/")]
public IHttpActionResult Delete(int id, int customerId)
{
    var file = new Models.File() { Id = id, CustomerId = customerId };
    db.Files.Attach(file);
    db.Files.Remove(file);

    db.SaveChanges();

    return Ok();
}
Ogglas
fuente
Aunque esto resolvió mi problema, sirvió para señalar el problema subyacente mencionado anteriormente en esta publicación sobre las versiones PKs y Row. Me había olvidado de agregar un mapa de esquema para una nueva tabla que se complicó aún más por el hecho de que el PK no siguió la regla de la convención de nomenclatura. <Nombre de la tabla> ID.
midohioboarder
3

Obtuve ese error cuando estaba eliminando algunas filas en la base de datos (en el bucle) y agregando las nuevas en la misma tabla.

La solución para mí fue crear dinámicamente un nuevo contexto en cada iteración de bucle.

Tony
fuente
Tuve que hacer lo mismo, aún no estoy seguro de por qué ocurrió el problema, pero esto funciona.
Jed Grant
3
    public void Save(object entity)
    {
        using (var transaction = Connection.BeginTransaction())
        {
        try
                {
                    SaveChanges();
                    transaction.Commit();
                }
                catch (OptimisticConcurrencyException)
                {
                    if (ObjectStateManager.GetObjectStateEntry(entity).State == EntityState.Deleted || ObjectStateManager.GetObjectStateEntry(entity).State == EntityState.Modified)
                        this.Refresh(RefreshMode.StoreWins, entity);
                    else if (ObjectStateManager.GetObjectStateEntry(entity).State == EntityState.Added)
                        Detach(entity);
                    AcceptAllChanges(); 
                    transaction.Commit();
                }
        }
    }
Prem Prakash
fuente
¿Pueden aclarar a qué se refiere 'esto' aquí y qué es ObjectStateManager? Estoy intentando esto en nuestra clase de repositorio base pero obtengo errores
Naomi
3

Esto también sucederá si está intentando insertar en una situación de restricción única, es decir, si solo puede tener un tipo de dirección por empleador e intenta insertar un segundo de ese mismo tipo con el mismo empleador, obtendrá el mismo problema .

O

Esto también podría suceder si todas las propiedades de objeto que se asignaron a ellos se les asignaron los mismos valores que tenían antes.

        using(var db = new MyContext())
        {
            var address = db.Addresses.FirstOrDefault(x => x.Id == Id);

            address.StreetAddress = StreetAddress; // if you are assigning   
            address.City = City;                   // all of the same values
            address.State = State;                 // as they are
            address.ZipCode = ZipCode;             // in the database    

            db.SaveChanges();           // Then this will throw that exception
        }
Serj Sagan
fuente
2

Si está intentando crear una asignación en su archivo edmx a una "Importación de funciones", esto puede ocasionar este error. Simplemente borre los campos para insertar, actualizar y eliminar que se encuentran en Detalles de mapeo para una entidad dada en su edmx, y debería funcionar. Espero haberlo dejado claro.

Mubarak
fuente
2

Obtuve esta excepción al adjuntar un objeto que no existía en la base de datos. Supuse que el objeto se cargó desde un contexto separado, pero si era la primera vez que el usuario visitaba el sitio, el objeto se creaba desde cero. Tenemos claves primarias de incremento automático, por lo que podría reemplazar

context.Users.Attach(orderer);

con

if (orderer.Id > 0) {
    context.Users.Attach(orderer);
}
Andrés
fuente
2

Bueno, tengo este mismo problema. Pero esto se debió a mi propio error. En realidad estaba guardando un objeto en lugar de agregarlo. Entonces este fue el conflicto.

Ali
fuente
2

Una forma de depurar este problema en un entorno de servidor SQL es usar el Sql Profiler incluido con su copia de SqlServer, o si usa la versión Express obtenga una copia de Express Profiler gratis de CodePlex mediante el siguiente enlace:

Perfilador Express

Al usar Sql Profiler puede obtener acceso a lo que sea enviado por EF a la base de datos. En mi caso esto ascendió a:

exec sp_executesql N'UPDATE [dbo].[Category]
SET [ParentID] = @0, [1048] = NULL, [1033] = @1, [MemberID] = @2, [AddedOn] = @3
WHERE ([CategoryID] = @4)
',N'@0 uniqueidentifier,@1 nvarchar(50),@2 uniqueidentifier,@3 datetime2(7),@4 uniqueidentifier',
@0='E060F2CA-433A-46A7-86BD-80CD165F5023',@1=N'I-Like-Noodles-Do-You',@2='EEDF2C83-2123-4B1C-BF8D-BE2D2FA26D09',
@3='2014-01-29 15:30:27.0435565',@4='3410FD1E-1C76-4D71-B08E-73849838F778'
go

Copié esto pegado en una ventana de consulta en SQL Server y lo ejecuté. Efectivamente, aunque se ejecutó, 0 registros se vieron afectados por esta consulta, por lo tanto, el error fue devuelto por EF.

En mi caso, el problema fue causado por el IdCategoría.

No se identificó ninguna Id. De categoría por el ID EF enviado a la base de datos, por lo tanto, 0 registros se vieron afectados.

Sin embargo, esto no fue culpa de EF, sino más bien un error "nulo" que se unía declaración en un controlador de vista que estaba enviando tonterías al nivel de datos.

rismo
fuente
2

Ninguna de las respuestas anteriores cubrió mi situación y la solución.

Código donde se produjo el error en el controlador MVC5:

        if (ModelState.IsValid)
        {
            db.Entry(object).State = EntityState.Modified; 
            db.SaveChanges(); // line that threw exception
            return RedirectToAction("Index");
        }

Recibí esta excepción cuando estaba guardando un objeto de una vista Editar. La razón por la que lo arrojó fue porque cuando volví a guardarlo, había modificado las propiedades que formaban la clave principal en el objeto. Por lo tanto, establecer su estado en Modificado no tenía ningún sentido para EF: era una entrada nueva, no una guardada anteriormente.

Puede resolver esto ya sea A) modificando la llamada guardada para Agregar el objeto, o B) simplemente no cambie la clave principal en la edición. Hice B).

J. Polfer
fuente
2

Cuando la respuesta aceptada decía " no va a terminar sobrescribiendo un cambio que su aplicación no sabía que sucedió ", estaba escéptico porque mi objeto se acababa de crear. Pero luego resulta que había un INSTEAD OF UPDATE, INSERT- TRIGGERadjunto a la tabla que estaba actualizando una columna calculada de la misma tabla.

Una vez que cambie esto a AFTER INSERT, UPDATE, estaba funcionando bien.

Mahesh
fuente
2

Esto me sucedió debido a una falta de coincidencia entre datetime y datetime2. Curiosamente, funcionó bien antes de que un probador descubriera el problema. El modelo My Code First incluía un DateTime como parte de la clave primaria:

[Key, Column(Order = 2)]  
public DateTime PurchasedDate { get; set; } = (DateTime)SqlDateTime.MinValue;

La columna generada es una columna de fecha y hora. Al llamar a SaveChanges, EF generó el siguiente SQL:

-- Region Parameters
DECLARE @0 Int = 2
DECLARE @1 Int = 25
DECLARE @2 Int = 141051
DECLARE @3 DateTime2 = '2017-07-27 15:16:09.2630000' --(will not equal a datetime value)
-- EndRegion
UPDATE [dbo].[OrganizationSurvey]
SET [OrganizationSurveyStatusId] = @0
WHERE ((([SurveyID] = @1) AND ([OrganizationID] = @2)) AND ([PurchasedDate] = @3))

Como intentaba hacer coincidir una columna de fecha y hora con un valor de fecha y hora2, no arrojó resultados. La única solución que se me ocurrió fue cambiar la columna a datetime2:

[Key, Column(Order = 2, TypeName = "DateTime2")]  
public DateTime PurchasedDate { get; set; } = (DateTime)SqlDateTime.MinValue;
R. Salisbury
fuente
1
Lo extraño de frente de trabajo no trabajo tiene que ver con el formato / base subyacente de datetimefrente datetime2. Esencialmente, algunos valores de milisegundos se evaluarán para una coincidencia, otros no. Me pasó lo mismo y también cambié a DateTime2.
xr280xr
+1 Desearía poder +100 en este caso para ti. Después de examinar muchos lugares, finalmente encontré esto y me di cuenta de que, de hecho, tenía una fecha y hora como parte de mi clave principal. Sí, esto realmente lo solucionó. Actualicé la columna a Datetime2 y funcionó. Ahora, mi problema es con Entity Framework para idear una consulta tan mala para esto que me obliga a hacer esto.
Catchops