【问题标题】:Self-referencing table in EF6EF6 中的自引用表
【发布时间】:2016-07-07 09:21:04
【问题描述】:

我认为这会很容易......我有一个表Module,它可以包含“基础”模块和“复合”模块(由 1-n 个基础组成)模块)。

所以我在 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)
)

我填写了几个基本模块:

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

现在我创建了一个 EF 6“代码优先,数据库逆向工程”模型并获得了这个 Module 类:

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

还有这个上下文类:

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

当我现在尝试用这段代码创建一个新的复合模块时,结果发现事情并不像我想象的那么容易.....

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

此代码导致错误(在尝试获取基本模块 #1 的行上):

System.Data.Entity.Core.EntityCommandExecutionException 未处理
HResult=-2146232004
Message=执行命令定义时发生错误。有关详细信息,请参阅内部异常。
来源=实体框架

内部异常:System.Data.SqlClient.SqlException
HResult=-2146232060
消息=无效的列名“Module_ModuleId”。

我在这里错过了什么?为什么 EF6 逆向工程代码不够智能,无法创建在这种情况下有效的模型??

到目前为止,我一直在使用 EF4 和数据库优先的方法,所以所有这些流畅的代码优先配置对我来说仍然有点神秘(和问题)......有人看到我的(大多数可能非常)明显的菜鸟错误??

PS:这是“现有数据库中的代码优先”逆向工程产生的代码 - 不是我自己的。那么为什么逆向工程输出的代码最终不起作用呢?

【问题讨论】:

  • 我在 EF6.1.3 上做你的场景,没有发生异常!
  • 如何访问 newCompound.BaseModules ?是 newCompound.Module1 吗?
  • @ArMaN:我也不能再重现这个问题了……这真的很奇怪……我得做更多的调查为什么它现在突然起作用了......

标签: entity-framework-6 code-first sql-server-2014 self-referencing-table


【解决方案1】:

试试我的生成器EntityFramework Reverse POCO Generator,看看它是否更适合你。

它生成了以下代码(有趣的东西在底部):

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-25
    • 1970-01-01
    • 1970-01-01
    • 2017-06-30
    • 1970-01-01
    • 2016-11-21
    • 1970-01-01
    • 2022-01-12
    相关资源
    最近更新 更多