web-dev-qa-db-fra.com

Code EF d'abord "Nom de colonne non valide 'Discriminator'" mais pas d'héritage

J'ai une table dans ma base de données appelée SEntries (voir ci-dessous l'instruction CREATE TABLE). Il a une clé primaire, quelques clés étrangères et rien de spécial à ce sujet. Ma base de données contient de nombreuses tables similaires à celle-ci, mais pour une raison quelconque, cette table s'est terminée par une colonne "Discriminator" sur la classe de proxy EF.

Voici comment la classe est déclarée en C #:

public class SEntry
{
    public long SEntryId { get; set; }

    public long OriginatorId { get; set; }
    public DateTime DatePosted { get; set; }
    public string Message { get; set; }
    public byte DataEntrySource { get; set; }
    public string SourceLink { get; set; }
    public int SourceAppId { get; set; }
    public int? LocationId { get; set; }
    public long? ActivityId { get; set; }
    public short OriginatorObjectTypeId { get; set; }
}

public class EMData : DbContext
{
    public DbSet<SEntry> SEntries { get; set; }
            ...
    }

Lorsque j'essaie d'ajouter une nouvelle ligne à cette table, j'obtiens le message d'erreur suivant:

System.Data.SqlClient.SqlException: Invalid column name 'Discriminator'.

Ce problème ne se produit que si vous héritez de votre classe C # d'une autre classe, mais que SEntry n'hérite de rien (comme vous pouvez le voir ci-dessus).

En plus de cela, une fois que je reçois l'info-bulle sur le débogueur lorsque je passe la souris sur l'instance EMData pour la propriété SEntries, il affiche:

base {System.Data.Entity.Infrastructure.DbQuery<EM.SEntry>} = {SELECT 
[Extent1].[Discriminator] AS [Discriminator], 
[Extent1].[SEntryId] AS [SEntryId], 
[Extent1].[OriginatorId] AS [OriginatorId], 
[Extent1].[DatePosted] AS [DatePosted], 
[Extent1].[Message] AS [Message], 
[Extent1].[DataEntrySource] AS [DataE...

Avez-vous des suggestions ou des idées pour aller au fond des choses? J'ai essayé de renommer la table, la clé primaire et quelques autres choses, mais rien ne fonctionne.

Table SQL:

CREATE TABLE [dbo].[SEntries](
[SEntryId] [bigint] IDENTITY(1125899906842624,1) NOT NULL,
[OriginatorId] [bigint] NOT NULL,
[DatePosted] [datetime] NOT NULL,
[Message] [nvarchar](500) NOT NULL,
[DataEntrySource] [tinyint] NOT NULL,
[SourceLink] [nvarchar](100) NULL,
[SourceAppId] [int] NOT NULL,
[LocationId] [int] NULL,
[ActivityId] [bigint] NULL,
[OriginatorObjectTypeId] [smallint] NOT NULL,
CONSTRAINT [PK_SEntries] PRIMARY KEY CLUSTERED 
(
[SEntryId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF,       ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[SEntries]  WITH CHECK ADD  CONSTRAINT [FK_SEntries_ObjectTypes] FOREIGN KEY([OriginatorObjectTypeId])
REFERENCES [dbo].[ObjectTypes] ([ObjectTypeId])
GO

ALTER TABLE [dbo].[SEntries] CHECK CONSTRAINT [FK_SEntries_ObjectTypes]
GO

ALTER TABLE [dbo].[SEntries]  WITH CHECK ADD  CONSTRAINT [FK_SEntries_SourceApps] FOREIGN KEY([SourceAppId])
REFERENCES [dbo].[SourceApps] ([SourceAppId])
GO

ALTER TABLE [dbo].[SEntries] CHECK CONSTRAINT [FK_SEntries_SourceApps]
GO
141
Marcelo Calbucci

Il s'avère que Entity Framework supposera que toute classe héritant d'une classe POCO mappée à une table de la base de données nécessite une colonne Discriminator, même si la classe dérivée ne sera pas enregistrée dans la base de données.

La solution est assez simple et il vous suffit d'ajouter [NotMapped] comme attribut de la classe dérivée.

Exemple:

class Person
{
    public string Name { get; set; }
}

[NotMapped]
class PersonViewModel : Person
{
    public bool UpdateProfile { get; set; }
}

À présent, même si vous mappez la classe Person à la table Person de la base de données, aucune colonne "Discriminator" ne sera créée car la classe dérivée a [NotMapped].

Comme astuce supplémentaire, vous pouvez utiliser [NotMapped] vers les propriétés que vous ne souhaitez pas associer à un champ de la base de données.

300
Marcelo Calbucci

Voici la syntaxe de l'API Fluent.

http://blogs.msdn.com/b/adonet/archive/2010/12/06/ef-feature-ctp5-fluent-api-samples.aspx

class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string FullName { 
        get {
            return this.FirstName + " " + this.LastName;
        }
    }
}

class PersonViewModel : Person
{
    public bool UpdateProfile { get; set; }
}


protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // ignore a type that is not mapped to a database table
    modelBuilder.Ignore<PersonViewModel>();

    // ignore a property that is not mapped to a database column
    modelBuilder.Entity<Person>()
        .Ignore(p => p.FullName);

}
42
Walter Stabosz

Je viens de rencontrer cela et mon problème était dû au fait que deux entités avec le System.ComponentModel.DataAnnotations.Schema.TableAttribute faisant référence à la même table.

par exemple:

[Table("foo")]
public class foo
{
    // some stuff here
}

[Table("foo")]
public class fooExtended
{
    // more stuff here
}

changer le second de foo en foo_extended a corrigé cela pour moi et j'utilise désormais Table par type (TPT)

8
Seph

Cela se produit également si vous avez une classe de base et une ou plusieurs sous-classes, au moins une des sous-classes introduisant des propriétés supplémentaires:

class Folder {
  [key]
  public string Id { get; set; }

  public string Name { get; set; }
}

// Adds no props, but comes from a different view in the db to Folder:
class SomeKindOfFolder: Folder {
}

// Adds some props, but comes from a different view in the db to Folder:
class AnotherKindOfFolder: Folder {
  public string FolderAttributes { get; set; }
}

Si ceux-ci sont mappés dans le DbContext comme ci-dessous, l'erreur "'Nom de colonne non valide' Discriminator '" se produit lorsqu'un type quelconque basé sur le type Folder de base est utilisé:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
  modelBuilder.Entity<Folder>().ToTable("All_Folders");
  modelBuilder.Entity<SomeKindOfFolder>().ToTable("Some_Kind_Of_Folders");
  modelBuilder.Entity<AnotherKindOfFolder>().ToTable("Another_Kind_Of_Folders");
}

J'ai trouvé que pour résoudre le problème, nous extrayions les accessoires de Folder dans une classe de base (qui n'est pas mappée dans OnModelCreating()) comme si - OnModelCreating ne devait pas être modifié:

class FolderBase {
  [key]
  public string Id { get; set; }

  public string Name { get; set; }
}

class Folder: FolderBase {
}

class SomeKindOfFolder: FolderBase {
}

class AnotherKindOfFolder: FolderBase {
  public string FolderAttributes { get; set; }
}

Cela élimine le problème, mais je ne sais pas pourquoi!

3
meataxe

Je reçois l'erreur dans une autre situation, et voici le problème et la solution:

J'ai 2 classes dérivées d'une même classe de base nommée LevledItem:

public partial class Team : LeveledItem
{
   //Everything is ok here!
}
public partial class Story : LeveledItem
{
   //Everything is ok here!
}

Mais dans leur DbContext, j'ai copié du code mais j'ai oublié de changer l'un des noms de classe:

public class MFCTeamDbContext : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //Other codes here
        modelBuilder.Entity<LeveledItem>()
            .Map<Team>(m => m.Requires("Type").HasValue(ItemType.Team));
    }

public class ProductBacklogDbContext : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //Other codes here
        modelBuilder.Entity<LeveledItem>()
            .Map<Team>(m => m.Requires("Type").HasValue(ItemType.Story));
    }

Oui, la deuxième carte <Équipe> devrait être Carte <Histoire>. Et cela m'a coûté une demi-journée pour le comprendre!

2
cheny

cette erreur arrive avec moi parce que j'ai fait ce qui suit

  1. J'ai changé le nom de colonne de la table dans la base de données
  2. (Je n'ai pas utilisé Update Model from database _ dans Edmx) I renommé manuellement Nom de la propriété pour correspondre au changement de schéma de base de données
  3. J'ai fait du refactoring pour changer le nom de la propriété dans la classe afin qu'il soit identique au schéma de base de données et aux modèles dans Edmx

Bien que tout cela, j'ai eu cette erreur

alors what to do

  1. J'ai supprimé le modèle d'Edmx
  2. Clic droit et Update Model from database

cela régénérera le modèle et le cadre d'entité willnotgive you this error

espérons que cela vous aide

1
Basheer AL-MOMANI

J'ai eu un problème similaire, pas exactement les mêmes conditions et puis j'ai vu ce post . J'espère que ça aide quelqu'un. Apparemment, j'utilisais l'un de mes modèles d'entité EF, une classe de base pour un type qui n'était pas spécifié en tant que base de données définie dans mon contexte de base de données. Pour résoudre ce problème, j'ai dû créer une classe de base possédant toutes les propriétés communes aux deux types et hériter de la nouvelle classe de base parmi les deux types.

Exemple:

//Bad Flow
    //class defined in dbcontext as a dbset
    public class Customer{ 
       public int Id {get; set;}
       public string Name {get; set;}
    }

    //class not defined in dbcontext as a dbset
    public class DuplicateCustomer:Customer{ 
       public object DuplicateId {get; set;}
    }


    //Good/Correct flow*
    //Common base class
    public class CustomerBase{ 
       public int Id {get; set;}
       public string Name {get; set;}
    }

    //entity model referenced in dbcontext as a dbset
    public class Customer: CustomerBase{

    }

    //entity model not referenced in dbcontext as a dbset
    public class DuplicateCustomer:CustomerBase{

       public object DuplicateId {get; set;}

    }
1
KwakuCsc

Ancien Q, mais pour la postérité ... cela se produit également (.NET Core 2.1) si vous avez une propriété de navigation à auto-référencement ("Parent" ou "Enfants" du même type) mais que le nom de la propriété Id n'est pas ce qu'il est EF attend. C'est-à-dire que j'avais une propriété "Id" sur ma classe appelée WorkflowBase et qu'elle contenait un tableau d'étapes enfants associées, qui étaient également de type WorkflowBase, et il essayait sans cesse de les associer. avec un "WorkflowBaseId" non existant (le nom que je suppose qu'il préfère comme défaut naturel/conventionnel). Je devais le configurer explicitement en utilisant HasMany(), WithOne() et HasConstraintName() pour lui indiquer comment parcourir. Mais j'ai passé quelques heures à penser que le problème résidait dans la cartographie "locale" de la clé primaire de l'objet, que j'ai essayé de corriger, mais qui fonctionnait probablement toujours.

1
user2403744