Kode EF Pertama “Nama kolom 'Diskriminator'” tidak valid tetapi tidak ada warisan

154

Saya memiliki tabel di database saya yang disebut SEntries (lihat di bawah pernyataan CREATE TABLE). Ini memiliki kunci utama, beberapa kunci asing dan tidak ada yang istimewa tentang itu. Saya memiliki banyak tabel di basis data saya yang mirip dengan yang itu, tetapi untuk beberapa alasan, tabel ini berakhir dengan kolom "Diskriminator" pada Kelas Proksi EF.

Ini adalah bagaimana kelas dideklarasikan dalam 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; }
            ...
    }

Ketika saya mencoba menambahkan baris baru ke tabel itu, saya mendapatkan kesalahan:

System.Data.SqlClient.SqlException: Invalid column name 'Discriminator'.

Masalah ini hanya terjadi jika Anda mewarisi kelas C # Anda dari kelas lain, tetapi SEntry tidak mewarisi dari apa pun (seperti yang Anda lihat di atas).

Selain itu, setelah saya mendapatkan tool-tip pada debugger ketika saya mengarahkan mouse ke instance EMData untuk properti SEntries, ini akan menampilkan:

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

Adakah saran atau ide untuk sampai ke bagian bawah masalah ini? Saya mencoba mengubah nama tabel, kunci utama dan beberapa hal lainnya, tetapi tidak ada yang berhasil.

SQL-Table:

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
Marcelo Calbucci
sumber
16
Untuk orang berikutnya yang akan menghabiskan waktu mencoba untuk mencari tahu ini, apa yang terjadi adalah bahwa di tempat lain pada kode, saya memiliki kelas yang diwarisi dari SEntry, meskipun itu bukan kelas yang akan disimpan di DB . Jadi yang perlu saya lakukan adalah menambahkan [NotMapped] sebagai atribut dari kelas itu!
Marcelo Calbucci
Saya mendapatkan kesalahan ini jika saya tidak menaruh [NotMapped] di kelas ApplicationUser di Identitymodel.cs
Heemanshu Bhalla

Jawaban:

319

Ternyata Kerangka Entitas akan menganggap bahwa setiap kelas yang mewarisi dari kelas POCO yang dipetakan ke tabel di database membutuhkan kolom Diskriminator, bahkan jika kelas turunan tidak akan disimpan ke DB.

Solusinya cukup sederhana dan Anda hanya perlu menambahkan [NotMapped]sebagai atribut dari kelas turunan.

Contoh:

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

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

Sekarang, bahkan jika Anda memetakan kelas Person ke tabel Person di database, kolom "Diskriminator" tidak akan dibuat karena kelas turunannya [NotMapped].

Sebagai kiat tambahan, Anda bisa menggunakan [NotMapped]properti yang tidak ingin Anda petakan ke bidang pada DB.

Marcelo Calbucci
sumber
7
ok jadi ada 3 jam dalam hidup saya; (tapi tyvm semua sama. Saya juga harus menambahkan hanya untuk menjadi jelas ... kelas turunan dapat jauh-jauh di sudut tidak dengan cara apa pun digunakan kembali: ketekunan dan EF masih akan mencoba dan menarik mereka ... sangat membingungkan
rism
12
Jika Anda tidak menemukan [NotMapped] harap tambahkan referensi ke: "System.ComponentModel.DataAnnotations" ke proyek dari "Kerangka Kerja Perakitan".
XandrUu
9
menggunakan System.ComponentModel.DataAnnotations.Schema;
ygaradon
6
tetapi dalam kasus saya, saya telah mewarisi kelas untuk menambahkan kolom dalam tabel db menggunakan kelas anak. Jadi saya tidak bisa menggunakan atribut notmapped ini untuk membuatnya berfungsi. Apa yang harus menjadi solusi saya dalam kasus ini?
sohaib mengikis
4
dalam kasus saya menambahkan tidak dipetakan tidak membantu. saya belum memetakan di semua viewmodels
Heemanshu Bhalla
44

Berikut adalah sintaks 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);

}
Walter Stabosz
sumber
Bukankah lebih baik menambahkan [NotMapped]atribut saja?
Keith
1
@Keith jawabanku adalah bagaimana mengabaikan kolom menggunakan Fluent API, yang tidak menggunakan atribut seperti [NotMapped]
Walter Stabosz
1
Keith ini adalah jawaban yang saya pikir karena sekarang bergerak menuju standar kode-pertama dan jawaban Walter lebih cocok untuk skenario ini terutama jika Anda akhirnya menggunakan migrasi db.
Tahir Khalid
Di mana Anda memiliki masalah yang berlawanan (yaitu dan kelas terikat EF yang mewarisi dari kelas POCO) ini adalah satu-satunya cara saya bisa membuatnya bekerja tanpa mencemari model data dengan EF.
Paul Michaels
8

Saya baru saja mengalami ini dan masalah saya disebabkan oleh memiliki dua entitas dengan System.ComponentModel.DataAnnotations.Schema.TableAttributemerujuk pada tabel yang sama.

sebagai contoh:

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

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

mengubah yang kedua dari foountuk foo_extendedmemperbaiki ini untuk saya dan saya sekarang menggunakan Table Per Type (TPT)

Seph
sumber
Ini tidak berhasil untuk saya:The entity types 'AtencionMedica' and 'AtencionMedicaAP' cannot share table 'AtencionMedicas' because they are not in the same type hierarchy
James Reategui
Terima kasih, membantu saya, memiliki masalah yang sama menggunakan API lancar:, var entity = modelBuilder.Entity<EntityObject>().ToTable("ENTITY_TABLE")dan kemudian baris lain menggunakan yang sama EntityObjectatau sama ENTITY_TABLE.
Mathijs Flietstra
4

Skenario lain di mana ini terjadi adalah ketika Anda memiliki kelas dasar dan satu atau lebih subclass, di mana setidaknya satu dari subclass memperkenalkan properti tambahan:

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

Jika ini dipetakan dalam DbContextseperti di bawah ini, kesalahan "'Nama kolom' Diskriminator '" salah terjadi ketika tipe apa pun berdasarkan Foldertipe dasar diakses:

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

Saya menemukan bahwa untuk memperbaiki masalah ini, kami mengekstrak alat peraga Folderke kelas dasar (yang tidak dipetakan OnModelCreating()) seperti itu - OnModelCreatingtidak boleh diubah:

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

Ini menghilangkan masalah, tapi saya tidak tahu kenapa!

meataxe
sumber
terima kasih, meataxe - biayanya satu atau dua jam, tapi bagian terburuknya, saya pasti punya masalah ini sebelumnya, karena saya sudah menyiapkan semua kelas dasar. Dumber saya setahun kemudian berkata, "Hei, sepertinya kelas dasar ini tidak melakukan apa-apa. Saya pikir saya hanya akan menghapusnya ..." Dan ada satu jam dalam hidup saya bahwa saya tidak akan pernah kembali. MENGAPA INI DIBUTUHKAN? Saya berharap saya lebih memahami EF.
Mata air
2

Saya mendapatkan kesalahan dalam situasi lain, dan inilah masalahnya dan solusinya:

Saya memiliki 2 kelas yang berasal dari kelas dasar yang sama bernama LevledItem:

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

Tetapi dalam DbContext mereka, saya menyalin beberapa kode tetapi lupa mengubah salah satu nama kelas:

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

Ya, Peta kedua <Tim> haruslah Peta <Cerita>. Dan saya harus membayar setengah hari untuk mengetahuinya!

cheny
sumber
2

Saya memiliki masalah yang sama, kondisi yang tidak persis sama dan kemudian saya melihat posting ini . Semoga ini bisa membantu seseorang. Rupanya saya menggunakan salah satu entitas entitas EF saya model kelas dasar untuk jenis yang tidak ditentukan sebagai set db dalam konteks db saya. Untuk memperbaiki masalah ini, saya harus membuat kelas dasar yang memiliki semua properti yang sama untuk dua jenis dan mewarisi dari kelas dasar baru di antara dua jenis.

Contoh:

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

    }
KwakuCsc
sumber
1

kesalahan ini terjadi pada saya karena saya melakukan hal berikut

  1. Saya mengubah nama Kolom dari tabel dalam basis data
  2. (Saya tidak menggunakan Update Model from databasedalam Edmx) Saya Mengganti nama secara manual Nama properti untuk mencocokkan perubahan dalam skema database
  3. Saya melakukan beberapa refactoring untuk mengubah nama properti di kelas menjadi sama dengan skema basis data dan model di Edmx

Meskipun semua ini, saya mendapat kesalahan ini

begitu what to do

  1. Saya menghapus model dari Edmx
  2. Klik kanan dan Update Model from database

ini akan membuat ulang model, dan kerangka kerja entitas will tidak give you this error

semoga ini membantu anda

Basheer AL-MOMANI
sumber
1

Q lama, tetapi untuk anak cucu ... itu juga terjadi (.NET Core 2.1) jika Anda memiliki properti navigasi referensi-sendiri ("Induk" atau "Anak-anak" dari jenis yang sama) tetapi nama properti Id bukan yang EF berharap. Yaitu, saya memiliki properti "Id" di kelas yang saya panggil WorkflowBase, dan memiliki serangkaian langkah anak terkait, yang juga bertipe WorkflowBase, dan terus mencoba mengaitkannya dengan "WorkflowBaseId" yang tidak ada (nama saya). misalkan lebih suka sebagai standar alami / konvensional). Aku harus secara eksplisit mengkonfigurasi menggunakan HasMany(), WithOne()dan HasConstraintName()menceritakannya bagaimana untuk melintasi. Tapi saya menghabiskan beberapa jam berpikir masalahnya ada di 'lokal' pemetaan kunci utama objek, yang saya coba untuk memperbaiki banyak cara yang berbeda tetapi yang mungkin selalu berhasil.

tntwyckoff
sumber