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()
чтобы рассказать, как пройти. Но я потратил несколько часов, думая, что проблема заключается в "локальном" отображении первичного ключа объекта, который я пытался исправить множеством разных способов, но, вероятно, всегда работал.