Код EF Спочатку "Недійсна назва стовпця" Дискримінатор "", але не має спадщини


154

У моїй базі даних є таблиця під назвою SEntries (див. Нижче оператор CREATE TABLE). У нього є первинний ключ, пара іноземних ключів і нічого особливого в ньому немає. У моїй базі даних багато таблиць, подібних до тієї, але чомусь ця таблиця опинилася у колонці "Дискримінатор" класу проксі EF.

Ось як оголошено клас у 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; }
            ...
    }

Коли я намагаюся додати новий рядок до цієї таблиці, я отримую помилку:

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

Ця проблема виникає лише в тому випадку, якщо ви успадковуєте свій клас C # від іншого класу, але SEntry не успадковує нічого (як ви бачите вище).

На додаток до цього, коли я отримую підказку інструменту на відладчику, коли я клацну мишкою на екземпляр EMData для властивості SEntries, він відображає:

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...

Будь-які пропозиції чи ідеї, де дійти до цього питання? Я спробував перейменувати таблицю, первинний ключ та кілька інших речей, але нічого не працює.

Таблиця 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

16
Для наступної людини, яка витратить якийсь час на те, щоб розібратися в цьому, що сталося, це те, що в іншому місці коду у мене був клас, який успадкований від SEntry, хоча це не клас, який коли-небудь зберігався б у БД . Отже, все, що мені потрібно було зробити, це додати [NotMapped] як атрибут цього класу!
— Марсело Кальбуччі

Я отримую цю помилку, якщо я не ставлю [NotMapped] на клас ApplicationUser в Identitymodel.cs
— Heemanshu Bhalla

Відповіді:


319

Виявляється, що Entity Framework буде припускати, що будь-який клас, який успадковує клас POCO, який відображається в таблиці бази даних, вимагає стовпця Discriminator, навіть якщо похідний клас не буде збережено в БД.

Рішення досить просте, і вам просто потрібно додати [NotMapped]як атрибут похідного класу.

Приклад:

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

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

Тепер, навіть якщо ви класуєте клас Person у таблицю Person у базі даних, стовпець "Дискримінатор" не буде створений, оскільки має похідний клас [NotMapped].

В якості додаткової підказки ви можете скористатися [NotMapped]властивостями, які ви не хочете відображати в полі в БД.


7
гаразд, це триває 3 години мого життя; (але все-таки tyvm. Я також повинен додати просто, щоб бути зрозумілим ... похідні класи можуть бути весь час у кутку, а не жодним чином використовуватися re: наполегливість та EF все ще спробую намалювати їх у ... дуже заплутано
— ризим

12
Якщо ви не знайдете [NotMapped], будь ласка, додайте посилання на: "System.ComponentModel.DataAnnotations" до проекту з "Асамблеї Framework".
— XandrUu

9
використання System.ComponentModel.DataAnnotations.Schema;
— ygaradon

6
але в моєму випадку я успадкував клас для додавання стовпця в таблицю db, використовуючи дочірній клас. Тож я не можу використовувати цей атрибут notmapped, щоб змусити його працювати. Яким має бути рішення в цьому випадку?
— sohaib javed

4
у моєму випадку додавання не відображеного не допомогло. я немає карти у всіх моделях перегляду
— Heemanshu Bhalla

44

Ось синтаксис Fluent API.

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);

}

Не було б краще просто додати [NotMapped]атрибут?
— Кіт

1
@Keith моя відповідь - як ігнорувати стовпець за допомогою API Fluent, який не використовує такі атрибути, як [NotMapped]
— Walter Stabosz

1
Кіт, це найкраща відповідь, я думаю, тому що зараз рухаємося до стандарту коду, і відповідь Уолтера краще підходить для цього сценарію, особливо якщо ви в кінцевому підсумку використовуєте db міграції.
— Тахір Халід

Якщо у вас є протилежна проблема (тобто клас EF, який успадковується від класу POCO), це був єдиний спосіб, коли я міг би так працювати, не забруднюючи модель даних за допомогою EF.
— Пол Майклс

8

Я щойно зіткнувся з цим, і моя проблема була викликана наявністю двох об'єктів, які System.ComponentModel.DataAnnotations.Schema.TableAttributeпосилаються на ту саму таблицю.

наприклад:

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

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

зміна другого з fooнаfoo_extended виправив для мене , і я зараз , використовуючи таблицю для кожного типу (TPT)


Для мене це не спрацювало:The entity types 'AtencionMedica' and 'AtencionMedicaAP' cannot share table 'AtencionMedicas' because they are not in the same type hierarchy
— James Reategui

Дякую, допомогли мені, виникла та сама проблема, використовуючи вільний API:, var entity = modelBuilder.Entity<EntityObject>().ToTable("ENTITY_TABLE")а потім інший рядок, використовуючи той самий EntityObjectчи той самий ENTITY_TABLE.
— Mathijs Flietstra

4

Інший сценарій, коли це відбувається, коли у вас є базовий клас та один або більше підкласів, де хоча б один із підкласів вводить додаткові властивості:

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; }
}

Якщо вони відображені у DbContextподібному вигляді нижче, помилка "" Недійсна назва стовпця "Дискримінатор" виникає, коли доступ до будь-якого типу на основі Folderбазового типу:

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");
}

Я виявив, що щоб вирішити проблему, ми витягуємо реквізити Folderбазового класу (який не відображається OnModelCreating()) таким чином - OnModelCreatingповинен бути незмінним:

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; }
}

Це усуває проблему, але я не знаю чому!


дякую, meataxe - це коштувало мені години чи двох, але найгірше було: я, мабуть, мав цю проблему раніше, бо в мене були створені базові класи. Опісля мені рік тому каже: "Гей, схоже, цей базовий клас нічого не робить. Я думаю, що я просто його зніму ..." І минула година мого життя, яку я ніколи не поверну. ЧОМУ ЦЕ ПОТРІБНО? Я б хотів, щоб я зрозумів EF краще.
— Wellspring

2

Я отримую помилку в іншій ситуації, і ось проблема і рішення:

У мене є 2 класи, похідні від того ж базового класу з назвою LevledItem:

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

Але в їх DbContext я скопіював якийсь код, але забув змінити одне з назв класу:

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));
    }

Так, на другій карті <Команда> має бути Карта <Історія>. І мені це коштувало півдня, щоб зрозуміти це!


2

У мене була подібна проблема, не зовсім однакові умови, і тоді я побачив цю посаду . Сподіваюся, це комусь допоможе. Мабуть, я використовував одну з моїх моделей об'єктів EF базовий клас для типу, який не був вказаний як набір db у моєму dbcontext. Щоб виправити цю проблему, мені довелося створити базовий клас, який мав би всі властивості, спільні для двох типів, і успадкував новий базовий клас серед двох типів.

Приклад:

//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

ця помилка трапляється зі мною, бо я зробив наступне

  1. Я змінив назву стовпця таблиці в базі даних
  2. (Я не використовувався Update Model from databaseв Edmx) Я перейменував вручну ім'я властивості, щоб відповідати зміні схеми бази даних
  3. Я зробив деякий рефакторинг, щоб змінити назву властивості в класі, щоб бути такою ж, як схема бази даних та моделі в Edmx

Хоча все це, я отримав цю помилку

так what to do

  1. Я видалив модель з Edmx
  2. Клацніть правою кнопкою миші та Update Model from database

це відновить модель, а структуру сутності will не give you this error

сподіваюся, що це допоможе тобі


1

Старий Q, але для нащадків ... це також трапляється (.NET Core 2.1), якщо у вас є навігаційне властивість, що самостійно посилається ("Батьківський" або "Діти" одного типу), але ім'я властивості Id - це не те EF очікує. Тобто, у мене в класі називався властивість "Id" WorkflowBase, і він мав масив пов'язаних дочірніх кроків, які також були типів WorkflowBase, і він намагався пов'язати їх з неіснуючим "WorkflowBaseId" (назва я припустимо, він вважає за краще природний / звичайний за замовчуванням). Я повинен був явним чином налаштувати його з допомогою HasMany(), WithOne()і HasConstraintName()сказати йому , як пройти. Але я провів кілька годин, думаючи, що проблема полягає у «локальному» відображенні первинного ключа об’єкта, який я намагався виправити купу різних способів, але це, мабуть, завжди працювало.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.