0

最初にコードと流暢な API を使用して、これらのテーブル リレーションシップのマッピングをセットアップするにはどうすればよいですか?

作成された 3 つのエンティティすべての poco がありますが、ほとんどの人は「中間」テーブル ( PlanUser ) の poco を持っていないため、適切な例を見つけることができませんでした。PlanUser.PlanCustomerId列をPlan.CustomerIdにマップするように EF に指示する必要がありますが、正しい結果が返されないか、現在のセットアップのように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プロファイラーは、これらのクエリが実行されていることを示しています。2 つ目は、顧客 ID 1 に加えて顧客 ID 43 を含める必要がありますが、含まれていません。その2行目を取得しない理由がわかりません。

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

カスケード削除を無効にする理由がわかりません。関連エンティティは他の 2 つのエンティティに依存しているため、おそらくこれを行うことはありません (つまりWillCascadeOnDelete(false)、両方の関係を削除します) 。PlanUser

この種のモデル (「ペイロードとの多対多の関係」と呼ばれることもあります) についてもう少し詳しく説明します:

于 2012-11-01T12:59:55.917 に答える
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);
        }
    }
于 2012-11-02T01:26:15.283 に答える