Код 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.