复合键的EF一对多关系

时间:2016-01-18 11:52:42

标签: c# entity-framework entity-framework-6

我在使用Entity Framework(6.3)检索关系使用复合键的实体的子集合时遇到问题。在下面的示例中,我正在尝试将Sprint与计划相关联,但Sprints子集合不断变回空白。

// Returns no sprints
var queryUsingSelect = await _dbContext
    .Plans
    .Select(p => new
    {
        p,
        p.Sprints
    })
    .ToListAsync();

// Returns a plan without sprints
var queryUsingInclude = await _dbContext
    .Plans
    .Include(p => p.Sprints)
    .ToListAsync();

// Returns me all sprints
var allSprints = await _dbContext
    .Plans
    .SelectMany(p => p.Sprints)
    .ToListAsync();

在上一个查询中,我使用SelectMany测试了它,它确实返回了Sprint,但实际上我需要能够使用Include来完成它。我在同一个项目中遇到了与另一个集合相同的问题,所以这似乎与我的方法一般存在问题。请注意,我已关闭延迟加载以防止意外的n + 1查询。

这是我的代码的精简版:

public class User
{
    public int UserId { get; set; }
    public string Name { get; set; }
}

public class Aspiration
{
    public int AspirationId { get; set; }
    public string Title { get; set; }
}

public class Plan
{
    public Plan()
    {
        Sprints = new List<Sprint>();
    }

    public int UserId { get; set; }
    public int AspirationId { get; set; }
    public virtual User User { get; set; }
    public virtual Aspiration Aspiration { get; set; }
    public virtual ICollection<Sprint> Sprints { get; set; }
}

public class Sprint
{
    public int SprintId { get; set; }
    public int UserId { get; set; }
    public int AspirationId { get; set; }
    public virtual Plan Plan { get; set; }
    public virtual User User { get; set; }
    public virtual Aspiration Aspiration { get; set; }
}

public class UserMap : EntityTypeConfiguration<User>
{
    public UserMap()
    {
        Property(t => t.Name)
            .HasMaxLength(100)
            .IsRequired();
    }
}

public class AspirationMap : EntityTypeConfiguration<Aspiration>
{
    public AspirationMap()
    {
        Property(t => t.Title)
            .HasMaxLength(100)
            .IsRequired();
    }
}

public class PlanMap : EntityTypeConfiguration<Plan>
{
    public PlanMap()
    {
        HasKey(s => new { s.UserId, s.AspirationId });

        HasRequired(s => s.User)
            .WithMany()
            .HasForeignKey(s => s.UserId);

        HasRequired(s => s.Aspiration)
            .WithMany()
            .HasForeignKey(s => s.AspirationId);
    }
}

public class SprintMap : EntityTypeConfiguration<Sprint>
{
    public SprintMap()
    {
        HasRequired(s => s.User)
            .WithMany()
            .HasForeignKey(s => s.UserId);

        HasRequired(s => s.Aspiration)
            .WithMany()
            .HasForeignKey(s => s.AspirationId);

        HasRequired(s => s.Plan)
            .WithMany(d => d.Sprints)
            .HasForeignKey(s => new { s.AspirationId, s.UserId });
    }
}

public class MyDbContext : DbContext
{
    static MyDbContext()
    {
        Database.SetInitializer<MyDbContext>(null);
    }

    public MyDbContext()
        : base(DbConstants.ConnectionStringName)
    {
        Configuration.LazyLoadingEnabled = false;
    }

    public DbSet<User> Users { get; set; }
    public DbSet<Aspiration> Aspirations { get; set; }
    public DbSet<Plan> Plans { get; set; }
    public DbSet<Sprint> Sprints { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        modelBuilder
            .Map(new UserMap())
            .Map(new AspirationMap())
            .Map(new PlanMap())
            .Map(new SprintMap())
            ;
    }
}

1 个答案:

答案 0 :(得分:1)

好吧,我在你的映射中看到了一些错误。

PlanSprint的FK必须与Plan的PK具有相同的顺序。所以替换这个:

HasRequired(s => s.Plan)
    .WithMany(d => d.Sprints)
    .HasForeignKey(s => new { s.AspirationId,s.UserId });

为此:

HasRequired(s => s.Plan)
    .WithMany(d => d.Sprints)
    .HasForeignKey(s => new { s.UserId, s.AspirationId });

进行这些更改后,我尝试运行您的代码,一切正常。