Entity Framework 4.2代码第一个流畅的api映射中间表

时间:2012-11-01 12:17:40

标签: entity-framework

如何使用代码优先和流畅的api设置这些表关系的映射?

我为所有三个实体创建了一个poco但是大多数人没有poco用于“中间”表( PlanUser )所以我找不到一个很好的例子。我需要告诉EF将 PlanUser.PlanCustomerId 列映射到 Plan.CustomerId ,但它要么不返回正确的结果,要么在当前设置中为< em>计划会抛出错误:

  

“指定的关联外键列'CustomerId'是   无效。指定的列数必须与数量匹配   主键列。“

enter image description here enter image description here

public class PlanUserMap : EntityTypeConfiguration<PlanUser>
{
    public PlanUserMap()
    {
        this.ToTable("PlanUser");
        this.HasKey(c => new { c.CustomerId, c.PlanCustomerId });

        this.HasRequired(c => c.Plan).WithMany().HasForeignKey(x => x.CustomerId).WillCascadeOnDelete(false);
        this.HasRequired(c => c.Customer).WithMany().HasForeignKey(x => x.CustomerId).WillCascadeOnDelete(false);
    }
}

public class PlanMap : EntityTypeConfiguration<Plan>
{
    public PlanMap()
    {
        this.ToTable("Plan");
        this.HasKey(c => c.CustomerId);
        // the below line returns only 1 row for any given customer even if there are multiple PlanUser rows for that customer
        //this.HasMany(c => c.PlanUsers).WithRequired().HasForeignKey(c => c.PlanCustomerId); 
        // this throws an error
        this.HasMany(c => c.PlanUsers).WithMany().Map(m => m.MapLeftKey("PlanCustomerId").MapRightKey("CustomerId"));
    }
}

public partial class CustomerMap : EntityTypeConfiguration<Customer>
{
    public CustomerMap()
    {
        this.ToTable("Customer");
        this.HasKey(c => c.Id);
        this.HasMany(c => c.PlanUsers).WithRequired().HasForeignKey(c => c.CustomerId);
    }
}

@Slauma,sql profiler显示正在执行的这些查询。第二个应该包括除客户ID 1之外的客户ID 43,但事实并非如此。我不知道为什么它没有检索到第二行。

exec sp_executesql N'SELECT 
[Extent1].[CustomerId] AS [CustomerId], 
[Extent1].[PlanCustomerId] AS [PlanCustomerId], 
[Extent1].[CreatedOnUtc] AS [CreatedOnUtc], 
[Extent1].[IsSelected] AS [IsSelected], 
[Extent1].[IsDeleted] AS [IsDeleted], 
[Extent1].[AccessRights] AS [AccessRights]
FROM [dbo].[PlanUser] AS [Extent1]
WHERE [Extent1].[CustomerId] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=43

exec sp_executesql N'SELECT 
[Extent1].[CustomerId] AS [CustomerId], 
[Extent1].[Name] AS [Name], 
[Extent1].[PlanTypeId] AS [PlanTypeId], 
[Extent1].[OrderId] AS [OrderId], 
[Extent1].[CreatedOnUtc] AS [CreatedOnUtc], 
[Extent1].[IsActive] AS [IsActive]
FROM [dbo].[Plan] AS [Extent1]
WHERE [Extent1].[CustomerId] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=1

以下是导致查询执行的C#代码:

    public List<Plan> GetPlans()
    {
        List<Plan> plans = new List<Plan>();

        // add each plan they have access rights to to the list
        foreach (var accessiblePlan in Customer.PlanUsers)
        {
            plans.Add(accessiblePlan.Plan);
        }

        return plans;
    }

2 个答案:

答案 0 :(得分:3)

我认为您所需要的实际上比您尝试的映射更简单:

public class PlanUserMap : EntityTypeConfiguration<PlanUser>
{
    public PlanUserMap()
    {
        this.ToTable("PlanUser");
        this.HasKey(pu => new { pu.CustomerId, pu.PlanCustomerId });

        this.HasRequired(pu => pu.Customer)
            .WithMany(c => c.PlanUsers)
            .HasForeignKey(pu => pu.CustomerId)
            .WillCascadeOnDelete(false);

        this.HasRequired(pu => pu.Plan)
            .WithMany(p => p.PlanUsers)
            .HasForeignKey(pu => pu.PlanCustomerId)
            .WillCascadeOnDelete(false);
    }
}

public class PlanMap : EntityTypeConfiguration<Plan>
{
    public PlanMap()
    {
        this.ToTable("Plan");
        this.HasKey(p => p.CustomerId);
    }
}

public partial class CustomerMap : EntityTypeConfiguration<Customer>
{
    public CustomerMap()
    {
        this.ToTable("Customer");
        this.HasKey(c => c.Id);
    }
}

我不确定为什么禁用级联删除。我可能不会这样做(即我会删除两个关系的WillCascadeOnDelete(false)),因为关联实体PlanUser依赖于其他两个实体。

以下是有关此类模型的更多详细信息(有时称为“与有效负载的多对多关系”):Create code first, many to many, with additional fields in association table

答案 1 :(得分:0)

好的,我明白了。感谢@Slauma的帮助!我们正在使用IOC(autofac)的存储库模式。我不应该首先在我的存储库服务中调用 Customer.PlanUsers 。在某个地方,我们开始使用存储库服务中的IOC解析 Customer 实体,以快速获取某些客户属性并将其置于只读变量中。这不可避免地给我们带来了麻烦,因为我们不是查询实体存储库本身,而是从 Customer 实体开始,期望它充满了我们需要的所有内容,而不是预先填充的。

    public List<Plan> GetPlans()
    {
        List<Plan> plans = new List<Plan>();
        var list = _planUserRepository.Table.Where(a => a.CustomerId == Customer.Id).ToList();
        foreach (var planUser in list)
        {
            plans.Add(planUser.Plan);
        }
    }