No se puede actualizar el EntitySet, porque tiene un DefiningQuery y no existe ningún elemento <UpdateFunction>

534

Estoy usando Entity Framework 1 con .net 3.5.

Estoy haciendo algo simple como esto:

var roomDetails = context.Rooms.ToList();

foreach (var room in roomDetails)
{        
   room.LastUpdated = DateTime.Now;
}

Recibo este error cuando intento hacer:

 context.SaveChanges();

Me sale el error:

No se puede actualizar EntitySet, porque tiene un DefiningQuery y no existe ningún elemento <UpdateFunction> en el elemento <ModificationFunctionMapping> para admitir la operación actual.

Estoy haciendo muchas actualizaciones en el contexto y no tengo ningún problema, es solo cuando trato de actualizar esta entidad en particular.

Toda mi búsqueda muestra lo mismo, que no hay una clave principal declarada en la entidad que estoy tratando de actualizar. Pero, por desgracia, tengo una clave primaria declarada ...

iKode
fuente
61
Cometí un error, no había una clave principal configurada en la mesa, ¡gracias por su tiempo! ¡Lo siento por los inconvenientes ocasionados!
iKode
1
Me pasó a mí, probablemente creé 1000 tablas con claves primarias y olvidé una, el mensaje de excepción no ayuda mucho
Peter Munnings,
1
excelente. Realmente olvidé agregar clave principal a la tabla. Tratemos de tener cuidado)
AEMLoviji

Respuestas:

1024

Suele ocurrir debido a una de las siguientes razones:

  • El conjunto de entidades se asigna desde la vista de base de datos
  • Una consulta de base de datos personalizada
  • La tabla de la base de datos no tiene una clave primaria

Después de hacerlo, es posible que aún necesite actualizar en el diseñador de Entity Framework (o, alternativamente, eliminar la entidad y luego agregarla) antes de dejar de recibir el error.

Ladislav Mrnka
fuente
2
Asegúrese de cambiar también store: Schema a solo Schema para ese EntitySet, si todavía tiene problemas.
Geoff
53
Luego, elimine y vuelva a crear la entidad porque la actualización no funciona correctamente en el diseñador de EF.
Suncat2000
48
PK fue la respuesta. ¡Gracias!
nrod
1
La actualización en el diseñador de EF funcionó bien para mí después de agregar la clave principal a la base de datos. Uso de EF 5.0 y .net 4.0
StillLearnin
1
Igual que aquí ! Thx ... tuvo que eliminar la tabla y volver a agregar a EF para que se la tomara
ajzeffer
90

Simplemente agregue una clave primaria a la tabla. Eso es. Problema resuelto.

ALTER TABLE <TABLE_NAME>
ADD CONSTRAINT <CONSTRAINT_NAME> PRIMARY KEY(<COLUMN_NAME>)
Jebastin J
fuente
13
y no olvides hacer clic en "Actualizar modelo desde la base de datos" en tu archivo .edmx
Bashar Abu Shamaa
@BasharAbuShamaa esta respuesta no es válida sin ese detalle.
Kehlan Krumme
66

Este es el caso para mí. Simplemente eliminar resultó en otro error. Seguí los pasos de esta publicación, excepto la última. Para su comodidad, copié los 4 pasos de la publicación que seguí para resolver el problema de la siguiente manera:

  1. Haga clic derecho en el archivo edmx, seleccione Abrir con, editor XML
  2. Localice la entidad en el elemento edmx: StorageModels
  3. Eliminar el DefiningQuery por completo
  4. Cambie el nombre de store:Schema="dbo"a Schema="dbo"(de lo contrario, el código generará un error que indica que el nombre no es válido)
kavitha Reddy
fuente
Muchas gracias, esto es exactamente lo que solucionó mi problema. Es bastante inquietante que esto no se haya solucionado en EF. Y, ¡es increíble que hayas descubierto esto!
Bicicleta Dave
Intenté eliminar la entidad y volver a agregarla. Recompilación Limpieza. Nada funcionó para mí excepto esto.
vintastic
1
Esto resolvió mi problema, pero no sé cómo se le ocurrieron las respuestas y por qué su sugerencia resolvió el problema.
swcraft
¿Qué sucede si necesita actualizar el modelo de base de datos? Hice un "Modelo de actualización de la base de datos" y dejó mi modelo totalmente inutilizable. Tuve que deshacer y comenzar de nuevo. Si hay una forma de evitar esto?
Gary
Ese es un problema realmente extraño. ¿Hay alguna información sobre cómo se produce este problema para evitarlo? No obstante - ayudó
r3dst0rm
41

Solo tenga en cuenta que tal vez su entidad tenga clave principal, pero su tabla en la base de datos no tiene clave principal .

Majid
fuente
1
¿Cómo superar, si no podemos cambiar la tabla de la base de datos?
Kai Hartmann
Si puede cambiar la tabla DB para que tenga una clave primaria, entonces el generador de código dejará de cometer los mismos errores, eliminar la clave de EF causará muchos otros problemas.
Chris Schaller
30

ACTUALIZACIÓN: He recibido algunos votos positivos sobre esto últimamente, así que pensé que le haría saber a la gente que el consejo que doy a continuación no es el mejor. Desde que originalmente comencé a burlarme de hacer Entity Framework en bases de datos antiguas sin clave, me he dado cuenta de que lo mejor que puedes hacer POR MUCHO es hacerlo primero con el código inverso. Hay algunos buenos artículos sobre cómo hacer esto. Simplemente sígalos y luego, cuando desee agregarle una clave, use anotaciones de datos para "falsificar" la clave.

Por ejemplo, supongamos que conozco mi tabla Orders, aunque no tiene una clave principal, se garantiza que solo tenga un número de pedido por cliente. Como esas son las dos primeras columnas de la tabla, configuraría las primeras clases de código para que se vean así:

    [Key, Column(Order = 0)]
    public Int32? OrderNumber { get; set; }

    [Key, Column(Order = 1)]
    public String Customer { get; set; }

Al hacer esto, básicamente estás fingiendo que EF cree que hay una clave agrupada compuesta por OrderNumber y Customer. Esto le permitirá hacer inserciones, actualizaciones, etc. en su tabla sin llave.

Si no está muy familiarizado con hacer primero el Código inverso, vaya y encuentre un buen tutorial sobre el Código de Entity Framework Primero. Luego, busque uno en Reverse Code First (que está haciendo Code First con una base de datos existente). Luego, vuelve aquí y mira mi consejo clave nuevamente. :)

Respuesta original :

Primero: como otros han dicho, la mejor opción es agregar una clave primaria a la tabla. Punto final. Si puedes hacer esto, no sigas leyendo.

Pero si no puede, o simplemente se odia a sí mismo, hay una manera de hacerlo sin la clave principal.

En mi caso, estaba trabajando con un sistema heredado (originalmente archivos planos en un AS400 portado a Access y luego portado a T-SQL). Así que tuve que encontrar un camino. Esta es mi solución Lo siguiente funcionó para mí usando Entity Framework 6.0 (lo último en NuGet a partir de este escrito).

  1. Haga clic derecho en su archivo .edmx en el Explorador de soluciones. Elija "Abrir con ..." y luego seleccione "Editor XML (Texto)". Vamos a editar a mano el código generado automáticamente aquí.

  2. Busque una línea como esta:
    <EntitySet Name="table_name" EntityType="MyModel.Store.table_name" store:Type="Tables" store:Schema="dbo" store:Name="table_nane">

  3. Retirar store:Name="table_name"del final.

  4. Cambiar store:Schema="whatever"aSchema="whatever"

  5. Mire debajo de esa línea y encuentre la <DefiningQuery>etiqueta. Tendrá una gran declaración de selección. Retire la etiqueta y su contenido.

  6. Ahora su línea debería verse así:
    <EntitySet Name="table_name" EntityType="MyModel.Store.table_name" store:Type="Tables" Schema="dbo" />

  7. Tenemos algo más que cambiar. Revisa tu archivo y encuentra esto:
    <EntityType Name="table_name">

  8. Cerca de allí probablemente verá algún texto comentado que le advierte que no tenía una clave principal identificada, por lo que la clave se ha inferido y la definición es una tabla / vista de solo lectura. Puedes dejarlo o eliminarlo. Lo borré.

  9. Debajo está la <Key>etiqueta. Esto es lo que Entity Framework va a utilizar para insertar / actualizar / eliminar. ASÍ QUE ASEGÚRESE DE HACER ESTO CORRECTAMENTE. La propiedad (o propiedades) en esa etiqueta debe indicar una fila identificable de forma única. Por ejemplo, supongamos que conozco mi tabla orders, aunque no tiene una clave principal, se garantiza que solo tenga un número de pedido por cliente.

Entonces el mío se ve así:

<EntityType Name="table_name">
              <Key>
                <PropertyRef Name="order_numbers" />
                <PropertyRef Name="customer_name" />
              </Key>

En serio, no hagas esto mal. Digamos que, aunque nunca debería haber duplicados, de alguna manera dos filas ingresan a mi sistema con el mismo número de pedido y nombre de cliente. Whooops! ¡Eso es lo que obtengo por no usar una llave! Entonces uso Entity Framework para eliminar uno. Como sé que el duplicado es el único pedido realizado hoy, hago esto:

var duplicateOrder = myModel.orders.First(x => x.order_date == DateTime.Today);
myModel.orders.Remove(duplicateOrder);

¿Adivina qué? ¡Acabo de eliminar tanto el duplicado como el original! Eso es porque le dije a Entity Framework que order_number / cutomer_name era mi clave principal. Entonces, cuando le dije que eliminara el pedido duplicado, lo que hizo en segundo plano fue algo como:

DELETE FROM orders
WHERE order_number = (duplicateOrder's order number)
AND customer_name = (duplicateOrder's customer name)

Y con esa advertencia ... ¡ahora deberías estar listo!

Pharylon
fuente
Encontré esta respuesta después de encontrar la misma solución al problema. Definitivamente la respuesta correcta! Solo definir una clave primaria como se menciona en otras respuestas no ayudará en muchos casos.
Obl Tobl
19

Esto también puede suceder si el modelo de datos no está actualizado.

Esperemos que esto ahorre frustración a otra persona :)

mob1lejunkie
fuente
6

Recibía el mismo mensaje de error, pero en mi caso estaba tratando de actualizar entidades derivadas de una relación de muchos a muchos usando un PJT (Tabla de unión pura).

Al leer las otras publicaciones, pensé que podría solucionarlo agregando un campo PK adicional a la tabla de unión ... Sin embargo, si agrega una columna PK a una tabla de unión, ya no es un PJT y pierde todo el ventajas del marco de entidades como el mapeo automático de relaciones entre las entidades.

Entonces, la solución en mi caso fue alterar la tabla de unión en la base de datos para hacer una PK que incluya AMBAS columnas de identificación externa.

Kerry Randolph
fuente
¿Es así como siempre ha funcionado la generación de EDMX? Estoy acostumbrado a trabajar con Code First, que no requiere una PK en una tabla de unión pura.
Michael Hornfeck
4

puede producirse un error, si su tabla no tiene clave primaria, en este caso la tabla es "solo lectura", y el comando db.SaveChanges () siempre traerá un error

Ruben.sar
fuente
4

Establezca la clave primaria, luego guarde la tabla y actualice, vaya a Model.edmx, elimine la tabla y vuelva a obtenerla.

Ali Raza
fuente
3

así que es cierto, solo agregue una clave primaria

Nota: asegúrese de que cuando esté actualizando su diagrama EF desde la base de datos que esté apuntando a la base de datos correcta , en mi caso la cadena de conexión apuntaba a una base de datos local en lugar de la base de datos de desarrollo actualizada, colegial error, lo sé, pero quería publicar esto porque puede ser muy frustrante si estás convencido de que has agregado la clave principal y sigues recibiendo el mismo error

Spyder
fuente
2

Tuve el mismo problema. Como decía este hilo, Mi tabla no tenía una PK, así que configuré la PK y ejecuté el código. Pero desafortunadamente el error vino nuevamente. Lo que hice después fue eliminar la conexión de la base de datos (eliminar el archivo .edmx en la carpeta Modelo de Solution Explorer) y recrearla. El error desapareció después de eso. Gracias a todos por compartir sus experiencias. Ahorra mucho tiempo.

Namal
fuente
1

Estaba recibiendo este problema porque estaba generando mi EDMX a partir de una base de datos existente (diseñada por otra persona, y utilizo el término 'diseñado' libremente).

Resulta que la mesa no tenía llaves en absoluto. EF estaba generando el modelo con muchas claves múltiples. Tuve que agregar una clave principal a la tabla db en SQL y luego actualicé mi modelo en VS.

Eso me lo arregló.

Rígido
fuente
1

Esta no es una respuesta nueva, pero ayudará a alguien que no esté seguro de cómo configurar la clave principal para su tabla. Use esto en una nueva consulta y ejecútelo. Esto establecerá la columna UniqueID como clave principal.

USE [YourDatabaseName]
GO

Alter table  [dbo].[YourTableNname]
Add Constraint PK_YourTableName_UniqueID Primary Key Clustered (UniqueID);
GO
JessS
fuente
1

ingrese la descripción de la imagen aquí

En mi caso, olvidé definir la clave principal de la tabla. Asigne como se muestra en la imagen y actualice su tabla desde "Actualizar modelo desde la base de datos" desde el archivo .edmx. Espero que ayude !!!

Yogesh Dangre
fuente
0

¡Agregar la clave principal también funcionó para mí!

Una vez hecho esto, aquí le mostramos cómo actualizar el modelo de datos sin eliminarlo:

Haga clic con el botón derecho en la página del diseñador de entidades edmx y en 'Actualizar modelo desde la base de datos'.

Abhishek Poojary
fuente
0

Tuve exactamente el mismo problema, desafortunadamente, agregar la clave principal no resuelve el problema. Así que así es como resuelvo el mío:

  1. Asegúrese de tener un primary keysobre la mesa, así que modifico mi tabla y agrego una clave principal.
  2. Delete the ADO.NET Entity Data Model (archivo edmx) donde uso para mapear y conectarme con mi base de datos.
  3. Add again a new file of ADO.NET Entity Data Model para conectarme con mi base de datos y para mapear las propiedades de mi modelo.
  4. Clean and rebuild the solution.

Problema resuelto.

Willy David Jr
fuente
0

simplemente agregue una clave principal a su tabla y luego vuelva a crear su EF

Sulyman
fuente
0

Solo tuve que eliminar la tabla del modelo y actualizar el modelo nuevamente para recuperar la tabla. Supongo que la clave principal se creó después de que la tabla se introdujo en el modelo.

Dangalg
fuente
0

Apareció este problema y creo que fue causado porque eliminé el índice en la clave principal de mis tablas y lo reemplacé con un índice en algunos de los otros campos de la tabla.

Después de eliminar el índice de clave principal y actualizar el edmx, las inserciones dejaron de funcionar.

Actualicé la tabla a la versión anterior, actualicé el edmx y todo volvió a funcionar.

Debo tener en cuenta que cuando abrí el EDMX para solucionar este problema, verificando si había una clave principal definida, la había. Así que ninguna de las sugerencias anteriores me estaba ayudando. Pero actualizar el índice en la clave primaria parecía funcionar.

armstb01
fuente
0

Abra su archivo .edmx en el editor XML y luego elimine la etiqueta de la etiqueta y también cambie store: Schema = "dbo" a Schema = "dbo" y reconstruya la solución ahora el error se resolverá y podrá guardar los datos.

Sharad Tiwari
fuente
0

Encontré que la respuesta original de actualizar el archivo .edmx funciona mejor en mi situación. Simplemente no estaba muy contento de alterar el modelo cada vez que se actualizaba desde la base de datos. Es por eso que escribí un archivo de plantilla de texto adicional, que se invoca automáticamente cuando el modelo ha cambiado, al igual que las entidades se generan recientemente. Lo publico aquí en este comentario. Para que funcione, asegúrese de nombrarlo como {nombre del modelo} .something.tt, y guárdelo en la misma carpeta que su carpeta .edmx. Lo llamé {nombre del modelo} .NonPkTables.tt. No genera un archivo por sí solo debido a la definición de extensión de archivo no válida en la segunda línea. Siéntase libre de usar.

<#@ template language="C#" debug="false" hostspecific="true"#>
<#@ output extension="/" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Data" #>
<#@ assembly name="System.Windows.Forms" #>
<#@ assembly name="System.Xml" #>
<#@ assembly name="System.Xml.Linq"#>
<#@ assembly name="%VS120COMNTOOLS%..\IDE\EntityFramework.dll" #>
<#@ assembly name="%VS120COMNTOOLS%..\IDE\Microsoft.Data.Entity.Design.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Windows.Forms" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.Xml.Linq" #>
<#@ import namespace="System.Globalization" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.Data.Entity.Core.Metadata.Edm" #>
<#@ import namespace="System.Data.Entity.Core.Mapping" #>
<#@ import namespace="System.CodeDom" #>
<#@ import namespace="System.CodeDom.Compiler" #>
<#@ import namespace="Microsoft.CSharp"#>
<#@ import namespace="System.Text"#>
<#@ import namespace="System.Diagnostics" #>

<#
    string modelFileName= this.Host.TemplateFile.Split('.')[0] + ".edmx";
    string edmxPath = this.Host.ResolvePath( modelFileName );

    // MessageBox.Show( this.Host.TemplateFile + " applied." );
    var modelDoc = XDocument.Load(edmxPath);
    var root = modelDoc.Root;
    XNamespace nsEdmx = @"http://schemas.microsoft.com/ado/2009/11/edmx";
    XNamespace ns = @"http://schemas.microsoft.com/ado/2009/11/edm/ssdl";

    var runtime = root.Elements(nsEdmx + "Runtime").First();
    var storageModels = runtime.Elements(nsEdmx + "StorageModels").First();
    XNamespace nsStore = @"http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator";

    var schema = storageModels.Elements(ns + "Schema").First();
    XNamespace nsCustomAnnotation = @"http://schemas.microsoft.com/ado/2013/11/edm/customannotation";

    var entityTypes = schema.Nodes().OfType<XComment>().Where(c => c.Value.Contains("warning 6002: The table/view"));
    bool changed = false;

    foreach (var node in entityTypes)
    {
        var element = node.ElementsAfterSelf().First();
        string entityName = element.Attribute("Name").Value;

        // Find EntitySet in EntityContainer.
        var entityContainer = schema.Elements(ns + "EntityContainer").First();
        var entitySet = entityContainer.Elements(ns + "EntitySet").First(s => s.Attribute("Name").Value == entityName);

        // Change "store:Schema" attribute to "Schema" attribute.
        var attribute = entitySet.Attribute(nsStore + "Schema");

        if (attribute != null)
        {
            string schemaName = entitySet.Attribute(nsStore + "Schema").Value;
            entitySet.Attribute(nsStore + "Schema").Remove();
            entitySet.Add(new XAttribute("Schema", schemaName));
            changed |= true;
        }

        // Remove the DefiningQuery element.
        var definingQuery = entitySet.Element(ns + "DefiningQuery");

        if (definingQuery != null)
        {
            definingQuery.Remove();
            changed |= true;        
            Debug.WriteLine(string.Format("Removed defining query of EntitySet {0}.", entityName));
        }
    }

    if (changed)
        modelDoc.Save(edmxPath);
#>
Arno Tolmeijer
fuente
-1

Me enfrenté al mismo mensaje de error para insertar un registro en una tabla que tenía una relación de Muchos a Muchos . Mi esquema de base de datos fue:

Student (Id , Name)
Course (Code , Title),
Student-Course (Student_ID, Course_Code)

Table Student y Course tienen las claves principales Id y Code respectivamente , mientras que la tabla Student-Course tiene dos claves externas asignadas con las tablas Student y Course.

Lógicamente, el esquema es correcto pero estaba cometiendo un error en la base de datos, porque cada tabla debería tener una clave primaria.

Mi definición sql para Student-Course fue:

CREATE TABLE [dbo].[Student-Course] (
    [StudentID]  VARCHAR (12) NOT NULL,
    [CourseCode] VARCHAR (10) NOT NULL,
    CONSTRAINT [FK_Student-Course_ToCourse] FOREIGN KEY ([Course_Code]) REFERENCES [dbo].[Course] ([Code]) ON DELETE CASCADE,
    CONSTRAINT [FK_Student-Course_ToStudent] FOREIGN KEY ([Student_ID]) REFERENCES [dbo].[Student] ([Id]) ON DELETE CASCADE
);

Hice un par de claves foráneas la clave principal de esta tabla y actualicé a:

CREATE TABLE [dbo].[Student-Course] (
    [StudentID]  VARCHAR (12) NOT NULL,
    [CourseCode] VARCHAR (10) NOT NULL,
    CONSTRAINT [PK_Student-Course] PRIMARY KEY CLUSTERED ([Student_ID] ASC, [Course_Code] ASC),
    CONSTRAINT [FK_Student-Course_ToCourse] FOREIGN KEY ([Course_Code]) REFERENCES [dbo].[Course] ([Code]) ON DELETE CASCADE,
    CONSTRAINT [FK_Student-Course_ToStudent] FOREIGN KEY ([Student_ID]) REFERENCES [dbo].[Student] ([Id]) ON DELETE CASCADE
);

Espero que resuelva problemas para algunos chicos.

Summar Raja
fuente
Esta pregunta ya tiene demasiadas respuestas. Además, casi cada respuesta dice "agregar una clave primaria" y una lo hace en el contexto de muchos a muchos.
Gert Arnold
Tiene razón, pero algunas personas agregan una identificación de clave primaria adicional en la tercera tabla, lo cual no es un buen enfoque.
Summar Raja
Como también dice la otra respuesta.
Gert Arnold