0

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

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

“指定的关联外键列‘CustomerId’无效。指定的列数必须与主键列数匹配。”

在此处输入图像描述 在此处输入图像描述

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

2 回答 2

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有点依赖于其他两个实体。

以下是有关这种模型的更多详细信息(有时称为“与有效负载的多对多关系”):首先创建代码,多对多,在关联表中具有附加字段

于 2012-11-01T12:59:55.917 回答
0

好的,我想通了。感谢@Slauma 的帮助!我们将存储库模式与 IOC(autofac) 一起使用。首先,我不应该在我的存储库服务中调用Customer.PlanUsers 。在某个地方,我们开始在存储库服务中使用 IOC 解析客户实体,以快速获取某些客户属性并将其放入只读变量中。这不可避免地让我们感到困扰,因为我们没有查询实体存储库本身,而是从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);
        }
    }
于 2012-11-02T01:26:15.283 回答