0

Ich dachte, das würde einfach sein ... Ich habe eine Situation, wo ich eine Tabelle Module, die "Basis" -Module enthalten kann, und "Compound" -Module (die aus bestehen 1-n Basismodule).Selbstreferenziert Tabelle in EF6

So habe ich diese beiden Tabellen in SQL Server 2014:

CREATE TABLE Module 
(
    ModuleId INT NOT NULL IDENTITY(1,1) 
     CONSTRAINT PK_Module PRIMARY KEY CLUSTERED, 
    ModuleName VARCHAR(100) 
) 

CREATE TABLE CompoundModule 
(
    CompoundModuleId INT NOT NULL 
     CONSTRAINT FK_CompoundModule_MainModule 
     FOREIGN KEY REFERENCES dbo.Module(ModuleId), 
    BaseModuleId INT NOT NULL 
     CONSTRAINT FK_CompoundModule_BaseModules 
     FOREIGN KEY REFERENCES dbo.Module(ModuleId), 

    CONSTRAINT PK_CompoundModule 
     PRIMARY KEY CLUSTERED(CompoundModuleId, BaseModuleId) 
) 

und ich in einigen Basismodulen gefüllt:

INSERT INTO dbo.Module (ModuleName) 
VALUES ('Base Module #1'), ('Base Module #2'), ('Base Module #3') 

Jetzt habe ich eine EF 6 „Code-first, Reverse -engineer aus der Datenbank“-Modell und bekommen diese Module Klasse:

[Table("Module")] 
public partial class Module 
{ 
    public Module() 
    { 
     Module1 = new HashSet<Module>(); 
     Module2 = new HashSet<Module>(); 
    } 

    public int ModuleId { get; set; } 
    public string ModuleName { get; set; } 

    public virtual ICollection<Module> Module1 { get; set; } 
    public virtual ICollection<Module> Module2 { get; set; } 
} 

und diese Kontextklasse:

public partial class ModuleCtx : DbContext 
{ 
    public ModuleCtx() : base("name=ModuleCtx") 
    { } 

    public virtual DbSet<Module> Module { get; set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.Entity<Module>() 
      .Property(e => e.ModuleName) 
      .IsUnicode(false); 

     modelBuilder.Entity<Module>() 
      .HasMany(e => e.Module1) 
      .WithMany(e => e.Module2) 
      .Map(m => m.ToTable("CompoundModule").MapLeftKey("BaseModuleId").MapRightKey("CompoundModuleId")); 
    } 
} 

Wenn ich jetzt versuchen, eine neue Verbindung Modul mit diesem Code zu erstellen, stellt sich heraus, sind die Dinge nicht ganz so einfach, wie ich dachte .....

using (ModuleCtx ctx = new ModuleCtx()) 
{ 
    Module newCompound = new Module(); 

    Module baseModule1 = ctx.Module.FirstOrDefault(m => m.ModuleId == 1); 
    Module baseModule3 = ctx.Module.FirstOrDefault(m => m.ModuleId == 3); 

    newCompound.BaseModules.Add(baseModule1); 
    newCompound.BaseModules.Add(baseModule3); 

    ctx.Module.Add(newCompound); 
    ctx.SaveChanges(); 
} 

Dieser Code ein Fehler verursacht (auf der Linie versucht, das Basismodul # 1 zu holen):

System.Data.Entity.Core.EntityCommandExecutionException unhandled war
HResult = -2146232004
Meldung = Beim Ausführen der Befehlsdefinition ist ein Fehler aufgetreten. Weitere Informationen finden Sie in der inneren Ausnahme.
Source = EntityFramework

Innerexception: System.Data.SqlClient.SqlException
HResult = -2146232060
Message = Ungültiger Spaltenname 'Module_ModuleId'.

Was fehlt mir hier ?? Und warum ist der Reverse-Engineering-Code von EF6 nicht intelligent genug, um ein Modell zu erstellen, das in diesem Fall funktioniert ??

Ich habe bisher EF4 mit Datenbank-First-Ansatz verwendet, so dass all diese fließende Code-First-Konfiguration ist immer noch ein Rätsel (und ein Problem) für mich ...... sieht jemand meine (höchstwahrscheinlich sehr) offensichtlicher Anfängerfehler ??

PS: das ist der Code, den die "Code-first-from-existing-Datenbank" Reverse-Engineering produziert - nicht mein eigenes. Warum funktioniert der Reverse Engineering-Ausgangscode am Ende nicht??

+0

ich tun, um Ihr Szenario auf EF6.1.3 und keine Ausnahme aufgetreten! – ArMaN

+0

Wie können Sie auf neue Compound.BaseModule zugreifen? ist es neuCompound.Module1? – ArMaN

+0

@ArMaN: Ich kann dieses Problem nicht mehr reproduzieren, auch nicht ..... das ist wirklich wirklich komisch ....... Ich werde ein bisschen mehr untersuchen müssen, warum es jetzt plötzlich funktioniert .. .... –

Antwort

1

Probieren Sie meinen Generator EntityFramework Reverse POCO Generator und sehen, ob das eine bessere Arbeit für Sie erledigt.

Es erzeugt den folgenden Code (interessante Sachen an der Unterseite):

public interface IMyDbContext : System.IDisposable 
{ 
    System.Data.Entity.DbSet<Module> Modules { get; set; } // Module 

    int SaveChanges(); 
    System.Threading.Tasks.Task<int> SaveChangesAsync(); 
    System.Threading.Tasks.Task<int> SaveChangesAsync(System.Threading.CancellationToken cancellationToken); 
} 

public class MyDbContext : System.Data.Entity.DbContext, IMyDbContext 
{ 
    public System.Data.Entity.DbSet<Module> Modules { get; set; } // Module 

    static MyDbContext() 
    { 
     System.Data.Entity.Database.SetInitializer<MyDbContext>(null); 
    } 

    public MyDbContext() 
     : base("Name=MyDbContext") 
    { 
    } 

    public MyDbContext(string connectionString) 
     : base(connectionString) 
    { 
    } 

    public MyDbContext(string connectionString, System.Data.Entity.Infrastructure.DbCompiledModel model) 
     : base(connectionString, model) 
    { 
    } 

    public MyDbContext(System.Data.Common.DbConnection existingConnection, bool contextOwnsConnection) 
     : base(existingConnection, contextOwnsConnection) 
    { 
    } 

    public MyDbContext(System.Data.Common.DbConnection existingConnection, System.Data.Entity.Infrastructure.DbCompiledModel model, bool contextOwnsConnection) 
     : base(existingConnection, model, contextOwnsConnection) 
    { 
    } 

    protected override void Dispose(bool disposing) 
    { 
     base.Dispose(disposing); 
    } 

    protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder) 
    { 
     base.OnModelCreating(modelBuilder); 

     modelBuilder.Configurations.Add(new ModuleConfiguration()); 
    } 

    public static System.Data.Entity.DbModelBuilder CreateModel(System.Data.Entity.DbModelBuilder modelBuilder, string schema) 
    { 
     modelBuilder.Configurations.Add(new ModuleConfiguration(schema)); 
     return modelBuilder; 
    } 
} 

public class Module 
{ 
    public int ModuleId { get; set; } // ModuleId (Primary key) 
    public string ModuleName { get; set; } // ModuleName (length: 100) 

    // Reverse navigation 
    public virtual System.Collections.Generic.ICollection<Module> BaseModule { get; set; } // Many to many mapping 
    public virtual System.Collections.Generic.ICollection<Module> CompoundModule { get; set; } // Many to many mapping 

    public Module() 
    { 
     BaseModule = new System.Collections.Generic.List<Module>(); 
     CompoundModule = new System.Collections.Generic.List<Module>(); 
    } 
} 

// Module 
public class ModuleConfiguration : System.Data.Entity.ModelConfiguration.EntityTypeConfiguration<Module> 
{ 
    public ModuleConfiguration() 
     : this("dbo") 
    { 
    } 

    public ModuleConfiguration(string schema) 
    { 
     ToTable("Module", schema); 
     HasKey(x => x.ModuleId); 

     Property(x => x.ModuleId).HasColumnName(@"ModuleId").IsRequired().HasColumnType("int").HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity); 
     Property(x => x.ModuleName).HasColumnName(@"ModuleName").IsOptional().IsUnicode(false).HasColumnType("varchar").HasMaxLength(100); 
     HasMany(t => t.CompoundModule).WithMany(t => t.BaseModule).Map(m => 
     { 
      m.ToTable("CompoundModule", "dbo"); 
      m.MapLeftKey("BaseModuleId"); 
      m.MapRightKey("CompoundModuleId"); 
     }); 
    } 
}