EF Code First“无效的列名'Discriminator'”但没有继承

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了EF Code First“无效的列名'Discriminator'”但没有继承相关的知识,希望对你有一定的参考价值。

我的数据库中有一个名为SEntries的表(参见下面的CREATE TABLE语句)。它有一个主键,几个外键,没有什么特别之处。我的数据库中有许多类似于那个表,但由于某种原因,该表最终在EF代理类上有一个“Discriminator”列。

这是在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不会从任何类继承(如上所示)。

除此之外,当我将鼠标悬停在SEntries属性的EMData实例上时,一旦我在调试器上获得了工具提示,它就会显示:

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
答案

事实证明,Entity Framework将假定从映射到数据库中的表的POCO类继承的任何类都需要Discriminator列,即使派生类不会保存到DB。

解决方案非常简单,您只需要添加[NotMapped]作为派生类的属性。

例:

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

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

现在,即使将Person类映射到数据库上的Person表,也不会创建“Discriminator”列,因为派生类具有[NotMapped]

作为附加提示,您可以将[NotMapped]用于不希望映射到DB上的字段的属性。

另一答案

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

}
另一答案

我刚刚遇到这个,我的问题是由两个实体都引用同一个表的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)

另一答案

发生这种情况的另一种情况是,当您有一个基类和一个或多个子类时,其中至少有一个子类引入了额外的属性:

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基类型的任何类型时,会出现“'无效列名'Discriminator'”错误:

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

这消除了这个问题,但我不知道为什么!

另一答案

我在另一种情况下得到错误,这是问题和解决方案:

我有两个派生自同一个基类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));
    }

是的,第二个Map <Team>应该是Map <Story>。我花了半天时间才弄明白!

另一答案

这个错误发生在我身上,因为我做了以下事情

  1. 我在数据库中更改了表的列名
  2. (我没有在Edmx中使用Update Model from database)我手动重命名属性名称以匹配数据库模式中的更改
  3. 我做了一些重构,将类中属性的名称更改为与Edmx中的数据库模式和模型相同

虽然所有这些,我得到了这个错误

所以what to do

  1. 我从Edmx删除了模型
  2. 右键单击和Update Model from database

这将重新生成模型,实体框架will不是give you this error

希望这能帮助你

另一答案

我有一个类似的问题,不完全相同的条件,然后我看到this post。希望它可以帮助某人。显然,我正在使用我的一个EF实体模型,这个类型的基类是未在我的dbcontext中指定为db set的类型。要解决这个问题,我必须创建一个基类,它具有两种类型共有的所有属性,并从两种类型中的新基类继承。

例:

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

    }

以上是关于EF Code First“无效的列名'Discriminator'”但没有继承的主要内容,如果未能解决你的问题,请参考以下文章

ef 用了code first from database 怎么增加新表

EF Code-First 学习之旅 Code First Conventions

EF之Code First代码优先

EF Code First 使用

20.翻译系列:Code-First中的数据库迁移技术EF 6 Code-First系列

EF Code-First 学习之旅 从已存在的数据库进行Code First