2

EF 4.1 の Code First でデータベースを生成する単純なクラスのペアがあります。

public class User
{
    public int UserId { get; set; }
    public string UserName { get; set; }
}

public class Purchase
{
    public int PurchaseId { get; set; }
    public int UserId { get; set; }
    public int? SalespersonUserId { get; set; }

    public User User { get; set; }
    public User SalespersonUser { get; set; }
}

public class NewItemsDataContext : DbContext
{
    public DbSet<User> Users { get; set; }
    public DbSet<Purchase> Purchases { get; set; }
}

私のプログラムでは、いくつかのデータを作成して書き込みます。

class Program
{
    static void Main(string[] args)
    {
        Database.SetInitializer<NewItemsDataContext>(new DropCreateDatabaseIfModelChanges<NewItemsDataContext>());

        using (NewItemsDataContext sadc = new NewItemsDataContext())
        {
            sadc.Users.Add(new User());

            sadc.SaveChanges();
        }
        using (NewItemsDataContext sadc = new NewItemsDataContext())
        {
            sadc.Purchases.Add(new Purchase() { UserId = 1 });
            sadc.SaveChanges();
        }
        using (NewItemsDataContext sadc = new NewItemsDataContext())
        {
            var sql = sadc.Purchases.Include(p => p.User);
            foreach (Purchase purchase in sql)
                Console.WriteLine(purchase.User.UserId.ToString());
        }
    }
}

Purchase レコードを読み返すと、 purchase.User が null であるという例外が発生することに注意してください。つまり、.Include はユーザーに対して何も取得しませんでした。ここで、OnModelCreating の salespersonUser ナビゲーション プロパティを無視すると (または単にコメントアウトすると):

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Purchase>().Ignore(p => p.SalespersonUser);

    base.OnModelCreating(modelBuilder);
}

コードは機能し、User は .Include にロードされます。

SalespersonUser nav プロパティを無視すると、作成されたデータベースは期待どおりに見えます。Purchase テーブルには PurchaseId、UserId、および SalespersonId があります。しかし、SalespersonUser nav プロパティを再度追加すると (無視しないでください)、テーブルには User_UserId と SalespersonUser_UserId (および元の UserId と SalespersonUserId) の 2 つのキーが追加されます。

また、生成された SQL は、問題が発生した場所を明確に示しています。

nav プロパティなし:

{SELECT 
[Extent1].[PurchaseId] AS [PurchaseId], 
[Extent1].[UserId] AS [UserId], 
[Extent1].[SalespersonUserId] AS [SalespersonUserId], 
[Extent2].[UserId] AS [UserId1], 
[Extent2].[UserName] AS [UserName]
FROM  [Purchases] AS [Extent1]
INNER JOIN [Users] AS [Extent2] ON [Extent1].[UserId] = [Extent2].[UserId]}

そして nav プロパティを使って:

{SELECT 
[Extent1].[PurchaseId] AS [PurchaseId], 
[Extent1].[UserId] AS [UserId], 
[Extent1].[SalespersonUserId] AS [SalespersonUserId], 
[Extent2].[UserId] AS [UserId1], 
[Extent2].[UserName] AS [UserName], 
[Extent1].[SalespersonUser_UserId] AS [SalespersonUser_UserId]
FROM  [Purchases] AS [Extent1]
LEFT OUTER JOIN [Users] AS [Extent2] ON [Extent1].[User_UserId] = [Extent2].[UserId]}

UserId をプルする方法に注目してください。ただし、User_UserId と結合し、左結合も同様です。SalespersonUserId は結合でも参照されません。レコードを書き込んだ後のデータベース内では、UserId が設定されていますが、User_UserID は null です。したがって、参加するものはなく、Included User に対して null を取得します。

これは EF のバグのように思えますが、設計上の理由がある可能性があります。もしそうなら、誰かが私のためにそれを片付けて、おそらくそれを回避するかもしれないいくつかの流暢なAPIについて説明できますか? 私は自分のナビゲーション プロパティに少し偏っています。

4

1 に答える 1

3

EF はナビゲーション プロパティに問題があります。これが、追加の FK を生成している理由です。

FK を nav プロパティの関係に明示的にマッピングするように、この流暢なマッピングを追加してみてください。

        modelBuilder.Entity<Purchase>()
            .HasOptional(p => p.SalespersonUser)
            .WithMany()
            .HasForeignKey(p => p.SalespersonUserId);

        modelBuilder.Entity<Purchase>()
            .HasRequired(p => p.User)
            .WithMany()
            .HasForeignKey(p => p.UserId);
于 2012-09-21T19:20:21.040 に答える