EF Code First "Недопустимое имя столбца" Дискриминатор ", но без наследования

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

Так объявлен класс в С#:

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

Эта проблема возникает только в том случае, если вы наследуете свой класс С# из другого класса, но 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

Ответ 1

Оказывается, что Entity Framework предположит, что для любого класса, который наследуется от класса POCO, который сопоставляется с таблицей в базе данных, требуется столбец Discriminator, даже если производный класс не будет сохранен в БД.

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

Пример:

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

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

Теперь, даже если вы сопоставляете класс Person с таблицей Person в базе данных, столбец "Discriminator" не будет создан, потому что производный класс имеет [NotMapped].

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

Ответ 2

Вот синтаксис 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);

}

Ответ 3

Я только что столкнулся с этим, и моя проблема была вызвана наличием двух объектов с System.ComponentModel.DataAnnotations.Schema.TableAttribute, относящихся к одной и той же таблице.

например:

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

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

изменение второго из foo в foo_extended исправлено для меня, и теперь я использую Table Per Type (TPT)

Ответ 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; }
}

Это устраняет проблему, но я не знаю, почему!

Ответ 5

Я получаю ошибку в другой ситуации, и вот проблема и решение:

У меня есть 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));
    }

Да, вторая Карта < Командa > должна быть Map < История > . И это стоило мне полдня, чтобы понять это!

Ответ 6

эта ошибка происходит со мной, потому что я сделал следующее

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

Хотя все это, я получил эту ошибку

so what to do

  • Я удалил модель из Edmx
  • Щелкните правой кнопкой мыши и Update Model from database

это приведет к восстановлению модели, а структура сущности will не give you this error

надеюсь, что это поможет вам

Ответ 7

У меня была похожая проблема, не совсем те же условия, и тогда я увидел этот пост. Надеюсь, это кому-нибудь поможет. Очевидно, я использовал одну из моих моделей сущностей EF - базовый класс для типа, который не был указан как набор БД в моем 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;}

    }

Ответ 8

Старый Q, но для потомков... это также случается (.NET Core 2.1), если у вас есть самореферентное свойство навигации ("Parent" или "Children" того же типа), но имя свойства Id не то, что EF ожидает. То есть у меня было свойство "Id" в моем классе под названием WorkflowBase, и у него был массив связанных дочерних шагов, которые также имели тип WorkflowBase, и он продолжал пытаться связать их с несуществующим "WorkflowBaseId" ( имя, которое я предпочитаю как естественное/обычное значение по умолчанию). Мне пришлось явно настроить его, используя HasMany(), WithOne() и HasConstraintName() чтобы рассказать, как пройти. Но я потратил несколько часов, думая, что проблема заключается в "локальном" отображении первичного ключа объекта, который я пытался исправить множеством разных способов, но, вероятно, всегда работал.