How do I setup the mapping for these table relationships using code first and the fluent api?
I have a poco for all three entities created but most people don't have a poco for the "intermediate" table (PlanUser) so I couldn't find a good example to go off of. I need to tell EF to map the PlanUser.PlanCustomerId column to Plan.CustomerId but it either doesn't return the right results OR as in the current setup the mapping for Plan throws the error:
"The specified association foreign key columns 'CustomerId' are invalid. The number of columns specified must match the number of primary key columns."
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 shows these queries being executed. The second one should include customer id 43 in addition to customer id 1 but it does not. I don't know why its not retrieving that second row.
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
Here is the C# code that causes the queries to execute:
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;
}