【问题标题】:Entity Framework (Code First) one to many - generates extra fields instead of using mapped keys实体框架(代码优先)一对多 - 生成额外字段而不是使用映射键
【发布时间】:2014-11-25 01:19:57
【问题描述】:

我正在尝试使用 Fluent API 和 .Include() 获取一些嵌套数据。我正在使用的数据库未标准化,我无法控制它。

“父”表是 TASK,“子”表是 STOCK_MOVEMENT,具有“许多库存移动到一个任务”的关系。

映射应该是从具有复合键 { "TSK_SITE", "TSK_TYPE" } 的 TASK 到具有复合键 { "MOV_SITE", "MOV_TYPE", "MOV_MOVE" } 的 STOCK_MOVEMENT。

article here 似乎最适合我手头的任务,尤其是“配置复合外键”部分。不幸的是,我的智能感知似乎没有为“HasForeignKey”行提示预期的字段,所以我不得不尝试其他东西......(欢迎思考!)

我尝试的是这样的:

            this.HasRequired(sm => sm.TestTask)
            .WithMany(t => t.Movements)
            .Map(m => m.MapKey("MOV_SITE", "MOV_TYPE"));

“HasRequired”和“HasOptional”都试过了...但是,最终由 EF 生成的 SQL 包含额外的字段,而不是映射到我指定的外键。

谁能解释一下我应该如何更改我的映射以获得正确的 SQL,好吗? 也非常欢迎指导性问题。

我在下面附上所有相关代码...

非常感谢!

维多利亚

public class TestTask : IMyObject
{
    public TestTask()
    {
        this.KeyFields = new string[] { "Site", "TaskType" };

        this.Movements = new HashSet<TestMovement>();
    }

    public string Site { get; set; }
    public string TaskType { get; set; }
    public string Key { get; set; }

    public virtual HashSet<TestMovement> Movements { get; set; }

    //... more code
}

internal partial class TestTask_Mapping : EntityTypeConfiguration<TestTask>
{
    public TestTask_Mapping()
    {
        this.HasKey(t => new { t.Site, t.TaskType });

        this.ToTable("TASK");

        this.Property(t => t.Site)
            .HasColumnName("TSK_SITE")
            .IsRequired();

        this.Property(t => t.TaskType)
            .HasColumnName("TSK_TYPE")
            .IsRequired();

        this.Property(t => t.Key)
            .HasColumnName("TSK_REF");
    }
}

public class TestMovement : IMyObject
{
    public TestMovement()
    {
        this.KeyFields = new string[] { "Site", "MoveType" };
    }

    public string Site { get; set; }
    public string MoveType { get; set; }
    public string Key { get; set; }

    public virtual TestTask TestTask { get; set; }

    // ... more code
}

public class TestStockMovement_Mapping : EntityTypeConfiguration<TestMovement>
{
    public TestStockMovement_Mapping()
    {
        this.HasKey(t => new { t.Site, t.MoveType });

        this.HasRequired(sm => sm.TestTask)
            .WithMany(t => t.Movements)
            .Map(m => m.MapKey("MOV_SITE", "MOV_TYPE"));

        this.Property(t => t.Site)
            .IsRequired();

        this.Property(t => t.MoveType)
            .IsRequired();

        this.ToTable("STOCK_MOVEMENT");

        //this.Property(t => t.Site).HasColumnName("MOV_SITE");
        //this.Property(t => t.MoveType).HasColumnName("MOV_TYPE");
        this.Property(t => t.Key).HasColumnName("MOV_MOVE");

    }
}

// In DbContext...

public DbSet<TestTask> TestTasks { get; set; }
public DbSet<TestMovement> TestStockMovements { get; set; }

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Configurations.Add(new TestTask_Mapping());
    modelBuilder.Configurations.Add(new TestStockMovement_Mapping());
}

// In the appropriate method in the repository ...

IQueryable<TestTask> testTasks = context.TestTasks.Include(t => t.Movements);

// Where testTasks results in the SQL with incorrect foreign key field references 
// (please see the picture that tells a thousand words below)...


为了澄清所涉及的数据库字段和表:我只提到了用作键的列以简化问题:

1)“TASK”表包含“TSK_SITE”和“TSK_TYPE”列,它们构成了它的复合键(+更多列)。

2)“STOCK_MOVEMENT”表包含“MOV_SITE”、“MOVE_TYPE”和“MOV_MOVE”列,它们构成其复合键的一部分(+更多列)。我没有在映射中使用“MOV_MOVE”,因为那里在父 TASK 表中没有等效列。

我应该为每个 TASK 记录检索一个或多个 STOCK_MOVEMENT 记录。

【问题讨论】:

  • 如果{ "MOV_SITE", "MOV_TYPE" }STOCK_MOVEMENT 表中的主键,那么TASK 表的外键是什么?如果关系是一对多的,它就不能再次是{ "MOV_SITE", "MOV_TYPE" }(正如你的映射所说)。如果 PK 和 FK 相同,则只能是一对一的关系。
  • 非常感谢您回答我的问题,Slauma!我在我的原始帖子中添加了一个编辑,澄清在 STOCK_MOVEMENT 表中还有一列是该表的复合键的一部分,但我没有添加到映射关系中。父 TASK 表中没有与该列等效的列,因此没有可映射的内容。我如何(应该)在我的代码中考虑该列以创建一对多?...

标签: c# entity-framework code-first composite-key


【解决方案1】:

TestTask 的映射似乎是正确的。对于TestMovement 的映射,您必须将完整键映射到所有三个部分:

this.HasKey(t => new { t.Site, t.MoveType, t.Key });

然后映射列名并将所有三个键属性设置为必填(键列不能为空):

this.Property(t => t.Site)
    .HasColumnName("MOV_SITE")
    .IsRequired();

this.Property(t => t.MoveType)
    .HasColumnName("MOV_TYPE")
    .IsRequired();

this.Property(t => t.Key)
    .HasColumnName("MOV_MOVE")
    .IsRequired();

然后 - 最重要的是 - 不要使用 MapKey 进行关系映射,因为您的外键列是模型类中的属性。在这种情况下,您总是必须使用HasForeignKey

this.HasRequired(sm => sm.TestTask)
    .WithMany(t => t.Movements)
    .HasForeignKey(t => new { t.Site, t.MoveType });

我知道您说过 HasForeignKey Intellisense 没有提供预期的属性(但代码是否仍然可以编译?)。这是您需要解决的另一个问题。但是使用MapKey 不是解决方案,也不会让您的模型和映射无处可去。

【讨论】:

  • 感谢您的详细说明,Slauma,我会在几个小时内试用它们...
  • 已经“从头开始”,现在智能感知正在工作,您的建议也很到位!感谢您的帮助,一切正常!
猜你喜欢
  • 2012-11-11
  • 1970-01-01
  • 1970-01-01
  • 2011-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-10
相关资源
最近更新 更多