web-dev-qa-db-ja.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
141

Entity Frameworkは、派生クラスがDBに保存されない場合でも、データベースのテーブルにマップされるPOCOクラスから継承するクラスにはDiscriminator列が必要であると想定していることがわかります。

解決策は非常に簡単で、派生クラスの属性として[NotMapped]を追加するだけです。

例:

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

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

これで、PersonクラスをデータベースのPersonテーブルにマップしても、派生クラスには[NotMapped]があるため、「Discriminator」列は作成されません。

追加のヒントとして、[NotMapped]を使用して、DBのフィールドにマップしたくないプロパティに使用できます。

300

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

}
42
Walter Stabosz

これに遭遇したばかりで、同じテーブルを参照するSystem.ComponentModel.DataAnnotations.Schema.TableAttributeを持つ2つのエンティティが原因で問題が発生しました。

例えば:

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

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

2番目のものをfooからfoo_extendedに変更すると、これが修正され、Table Per Type(TPT)を使用するようになりました

8
Seph

これが発生する別のシナリオは、基本クラスと1つ以上のサブクラスがあり、少なくとも1つのサブクラスが追加のプロパティを導入する場合です。

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ベースタイプに基づくタイプにアクセスすると、「 'Invalid column name' 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; }
}

これにより問題は解消されますが、理由はわかりません!

3
meataxe

別の状況でエラーが発生しましたが、ここに問題と解決策があります:

LevledItemという名前の同じ基本クラスから派生した2つのクラスがあります。

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

しかし、DbContextでは、いくつかのコードをコピーしましたが、クラス名の1つを変更することを忘れました。

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番目のMap <Team>はMap <Story>である必要があります。そして、それを理解するのに半日かかりました!

2
cheny

私は次のことをしたので、このエラーは私で起こります

  1. データベースのテーブルの列名を変更しました
  2. (EdmxでUpdate Model from databaseを使用しませんでした)データベーススキーマの変更に合わせてプロパティ名を手動で変更しました
  3. クラスのプロパティの名前をEdmxのデータベーススキーマおよびモデルと同じになるように変更するために、いくつかのリファクタリングを行いました

このすべてですが、このエラーが発生しました

what to do

  1. Edmxからモデルを削除しました
  2. 右クリックしてUpdate Model from database

これにより、モデルとエンティティフレームワークが再生成されますwillnotgive you this error

これがお役に立てば幸いです

1

まったく同じ条件ではなく、同様の問題が発生したので、 この投稿 を見ました。それが誰かを助けることを願っています。どうやら、EFエンティティモデルの1つを使用して、dbcontextでdbセットとして指定されていないタイプの基本クラスをモデル化していたようです。この問題を解決するには、2つのタイプに共通するすべてのプロパティを持つ基本クラスを作成し、2つのタイプ間で新しい基本クラスから継承する必要がありました。

例:

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

古いQですが、後世のために...自己参照ナビゲーションプロパティ(同じタイプの「親」または「子供」)があり、Idプロパティ名がそうではない場合にも発生します(.NET Core 2.1) EFは期待しています。つまり、クラスにはWorkflowBaseという名前の「Id」プロパティがあり、関連する子ステップの配列もありました。これらのステップもWorkflowBase型であり、存在しない「WorkflowBaseId」(名前は自然/従来のデフォルトとして好むと思います)。 HasMany()WithOne()、およびHasConstraintName()を使用して明示的に設定し、トラバース方法を指示する必要がありました。しかし、私は問題がオブジェクトの主キーの「ローカル」マッピングにあると考えて数時間を費やしました。これはさまざまな方法を修正しようとしましたが、おそらく常に機能していました。

1
user2403744