如何使用代码优先和流畅的api设置这些表关系的映射?
我为所有三个实体创建了一个poco但是大多数人没有poco用于“中间”表( PlanUser )所以我找不到一个很好的例子。我需要告诉EF将 PlanUser.PlanCustomerId 列映射到 Plan.CustomerId ,但它要么不返回正确的结果,要么在当前设置中为< em>计划会抛出错误:
“指定的关联外键列'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;
}
答案 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);
}
}