EF Code ก่อน“ ชื่อคอลัมน์ไม่ถูกต้อง 'Discriminator'” แต่ไม่มีการสืบทอด


154

ฉันมีตารางในฐานข้อมูลชื่อ SEntries (ดูด้านล่างคำสั่ง CREATE TABLE) มันมีคีย์หลักสองสามคีย์ต่างประเทศและไม่มีอะไรพิเศษเกี่ยวกับมัน ฉันมีตารางจำนวนมากในฐานข้อมูลของฉันคล้ายกับที่หนึ่ง แต่ด้วยเหตุผลบางอย่างตารางนี้จบลงด้วยคอลัมน์ "Discriminator" ใน EF Proxy Class

นี่คือวิธีการประกาศคลาสใน 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 ไม่ได้รับมรดกจากสิ่งใด (ตามที่คุณเห็นด้านบน)

นอกจากนั้นเมื่อฉันได้รับเคล็ดลับเครื่องมือบนดีบักเกอร์เมื่อฉันเลื่อนเมาส์ไปที่อินสแตนซ์ 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

16
สำหรับคนต่อไปที่จะใช้เวลาพยายามคิดสิ่งนี้สิ่งที่เกิดขึ้นคือในที่อื่นในรหัสฉันมีคลาสที่สืบทอดมาจาก SEntry แม้ว่าจะไม่ใช่คลาสที่จะถูกเก็บไว้ใน DB . ดังนั้นสิ่งที่ฉันต้องทำก็คือเพิ่ม [NotMapped] เป็นคุณสมบัติของคลาสนั้น!
Marcelo Calbucci

ฉันได้รับข้อผิดพลาดนี้หากฉันไม่ใส่ [NotMapped] ในคลาส ApplicationUser ใน Identitymodel.cs
Heemanshu Bhalla

คำตอบ:


319

ปรากฎว่า Entity Framework จะถือว่าคลาสใดก็ตามที่สืบทอดจากคลาส POCO ที่แมปไปยังตารางในฐานข้อมูลนั้นต้องการคอลัมน์ Discriminator แม้ว่าคลาสที่ได้รับจะไม่ถูกบันทึกลงในฐานข้อมูลก็ตาม

การแก้ปัญหาค่อนข้างง่ายและคุณเพียงแค่ต้องเพิ่ม[NotMapped]เป็นแอตทริบิวต์ของคลาสที่ได้รับ

ตัวอย่าง:

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

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

ตอนนี้แม้ว่าคุณแมชั้นบุคคลในตารางบุคคลในฐานข้อมูลเป็น "discriminator คอลัมน์" [NotMapped]จะไม่สามารถสร้างชั้นเรียนมาเพราะมี

เป็นเคล็ดลับเพิ่มเติมคุณสามารถใช้[NotMapped]คุณสมบัติที่คุณไม่ต้องการแมปกับเขตข้อมูลบนฐานข้อมูล


7
ตกลงดังนั้นจะมีชีวิตของฉันไป 3 ชั่วโมง (แต่ tyvm เหมือนกันทั้งหมดฉันควรจะเพิ่มให้ชัดเจน ... คลาสที่ได้รับสามารถอยู่ในมุมที่ไม่ได้ใช้ซ้ำ: การคงอยู่และ EF จะยังคงพยายามวาดพวกเขาใน ... สับสนมาก
rism

12
หากคุณไม่พบ [NotMapped] โปรดเพิ่มการอ้างอิงถึง: "System.ComponentModel.DataAnnotations" ไปยังโครงการจาก "Assembly Framework"
XandrUu

9
ใช้ System.ComponentModel.DataAnnotations.Schema;
ygaradon

6
แต่ในกรณีของฉันฉันได้รับคลาสเพื่อเพิ่มคอลัมน์ในตาราง db โดยใช้คลาสลูก ดังนั้นฉันจึงไม่สามารถใช้คุณลักษณะที่ไม่มีการแมปนี้เพื่อให้ทำงานได้ ในกรณีนี้ฉันควรจะแก้ปัญหาอะไร
sohaib javed

4
ในกรณีของฉันเพิ่มไม่แมปไม่ได้ช่วย ฉันยังไม่ได้แมปในทุก viewmodels
Heemanshu Bhalla

44

นี่คือไวยากรณ์ 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);

}

จะเป็นการดีกว่าที่จะเพิ่ม[NotMapped]แอตทริบิวต์หรือไม่
Keith

1
@Keith คำตอบของฉันคือวิธีการละเว้นคอลัมน์โดยใช้ Fluent API ซึ่งไม่ได้ใช้แอตทริบิวต์เช่น [NotMapped]
Walter Stabosz

1
Keith นี่เป็นคำตอบที่ฉันคิดว่าเพราะตอนนี้ย้ายไปสู่มาตรฐานรหัสแรกและคำตอบของ Walter เหมาะสำหรับสถานการณ์นี้โดยเฉพาะถ้าคุณจบลงด้วยการย้ายฐานข้อมูล
Tahir Khalid

ในกรณีที่คุณมีปัญหาตรงข้าม (เช่นและคลาสที่เชื่อมโยงกับ EF ที่สืบทอดมาจากคลาส POCO) นี่เป็นวิธีเดียวที่ฉันจะสามารถทำงานได้โดยไม่ทำให้โมเดลข้อมูลกับ EF เป็นมลทิน
Paul Michaels

8

ฉันเพิ่งพบสิ่งนี้และปัญหาของฉันเกิดจากการที่มีสองเอนทิตีทั้งที่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)


สิ่งนี้ไม่ได้ผลสำหรับฉัน:The entity types 'AtencionMedica' and 'AtencionMedicaAP' cannot share table 'AtencionMedicas' because they are not in the same type hierarchy
James Reategui

ขอบคุณช่วยให้ฉันมีปัญหาเดียวกันโดยใช้ API ได้อย่างคล่องแคล่ว: var entity = modelBuilder.Entity<EntityObject>().ToTable("ENTITY_TABLE")แล้วสายอื่นใช้อย่างใดอย่างหนึ่งที่เหมือนกันหรือเหมือนกันEntityObject ENTITY_TABLE
Mathijs Flietstra

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ลักษณะด้านล่างข้อผิดพลาด "'ชื่อคอลัมน์ไม่ถูกต้อง' Discriminator '" จะเกิดขึ้นเมื่อมีการเข้าถึงประเภทใด ๆ ที่อิงตาม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; }
}

สิ่งนี้ช่วยลดปัญหา แต่ฉันไม่รู้ว่าทำไม!


ขอบคุณ meataxe - ที่เสียค่าใช้จ่ายฉันหนึ่งหรือสองชั่วโมง แต่ส่วนที่เลวร้ายที่สุดคือฉันต้องมีปัญหานี้มาก่อนเพราะฉันมีการเรียนพื้นฐานทั้งหมด อีกหนึ่งปีให้ฉันพูดว่า "เฮ้ดูเหมือนว่าคลาสเบสนี้จะไม่ทำอะไรเลยฉันคิดว่าฉันจะเอามันออกไป ... " และมีชีวิตหนึ่งชั่วโมงของฉันที่ฉันจะไม่มีวันได้กลับมา ทำไมต้องมีสิ่งนี้ ฉันหวังว่าฉันจะเข้าใจ EF ได้ดีขึ้น
Wellspring

2

ฉันได้รับข้อผิดพลาดในสถานการณ์อื่นและนี่คือปัญหาและวิธีแก้ไข:

ฉันมี 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));
    }

ใช่แผนที่ที่สอง <ทีม> ควรเป็นแผนที่ <เรื่องราว> และฉันใช้เวลาครึ่งวันกว่าจะคิดออก!


2

ฉันมีปัญหาที่คล้ายกันไม่ใช่เงื่อนไขเดียวกันแล้วฉันเห็นโพสต์นี้ หวังว่าจะช่วยใครซักคน เห็นได้ชัดว่าฉันใช้หนึ่งในโมเดลเอนทิตี้ของ EF ของฉันเป็นคลาสพื้นฐานสำหรับประเภทที่ไม่ได้ระบุเป็นชุด db ใน 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;}

    }

1

ข้อผิดพลาดนี้เกิดขึ้นกับฉันเพราะฉันทำสิ่งต่อไปนี้

  1. ฉันเปลี่ยนชื่อคอลัมน์ของตารางในฐานข้อมูล
  2. (ฉันไม่ได้ใช้Update Model from databaseใน Edmx) ฉันเปลี่ยนชื่อชื่อคุณสมบัติด้วยตนเองเพื่อให้ตรงกับการเปลี่ยนแปลงในสคีมาฐานข้อมูล
  3. ฉันทำการเปลี่ยนโครงสร้างใหม่เพื่อเปลี่ยนชื่อของคุณสมบัติในคลาสให้เหมือนกับ schema ฐานข้อมูลและโมเดลใน Edmx

แม้ว่าทั้งหมดนี้ฉันได้รับข้อผิดพลาดนี้

ดังนั้น what to do

  1. ฉันลบแบบจำลองจาก Edmx
  2. คลิกขวาและ Update Model from database

สิ่งนี้จะสร้างโมเดลใหม่และกรอบงานเอนทิตีwill ไม่ give you this error

หวังว่านี่จะช่วยคุณได้


1

Old Q แต่สำหรับลูกหลาน ... มันเกิดขึ้นได้ด้วย (. NET Core 2.1) หากคุณมีคุณสมบัติการนำทางอ้างอิงตัวเอง ("ผู้ปกครอง" หรือ "เด็ก ๆ " ประเภทเดียวกัน) แต่ชื่อคุณสมบัติ Id ไม่ใช่สิ่งที่ EF คาดว่า นั่นคือฉันมีคุณสมบัติ "รหัส" ในชั้นเรียนของฉันที่เรียกว่าWorkflowBaseและมีขั้นตอนของเด็กที่เกี่ยวข้องซึ่งเป็นประเภทWorkflowBaseและมันพยายามที่จะเชื่อมโยงพวกเขากับ "WorkflowBaseId" ที่ไม่มีอยู่จริง (ชื่อ i สมมติว่าเป็นค่าเริ่มต้นที่เป็นธรรมชาติ / ธรรมดา) ผมต้องชัดเจนกำหนดค่าใช้HasMany(), WithOne()และHasConstraintName()บอกว่าวิธีการที่จะขวาง แต่ฉันใช้เวลาสองสามชั่วโมงคิดว่าปัญหาคือใน 'ภายใน' การจับคู่คีย์หลักของวัตถุซึ่งฉันพยายามที่จะแก้ไขวิธีต่าง ๆ มากมาย แต่ที่อาจทำงานได้เสมอ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.