Why does EF Code First [InverseProperty] attribute fail to work when used with [ForeignKey] attribute?

自作多情 提交于 2020-01-02 07:13:26

问题


Using: EF 4.3.1, Visual Studio 2010, SQL CE 4.0

My understanding is that when declaring Foreign Keys with DataAnnotation in EF, it can be done either of the following ways:

Option 1-

[ForeignKey("Player1Home")]
public long? HPlayer1Id { get; set; }

public virtual Player Player1Home { get; set; }

Option 2-

public long? HPlayer1Id { get; set; }

[ForeignKey("HPlayer1Id")]
public virtual Player Player1Home { get; set; }

Problem:

When the InverseProperty DataAnnotation gets used with Option 2 an extra column gets generated in the database (Player1Home_Id) in addition to HPlayer1Id.
[Table("Matches")]
public class Match
{
    [Key]
    public long Id { get; set; }

    //-- Option 1 - THIS WORKS GREAT --//
    public long? HPlayer1Id { get; set; }
    [ForeignKey("HPlayer1Id")]
    public virtual Player Player1Home { get; set; }

    //-- Option 2 - THIS DOES NOT WORK, it generates an extra column in the database --//
    [ForeignKey("Player1Home")]
    public long? HPlayer1Id { get; set; }
    public virtual Player Player1Home { get; set; }
}

[Table("Players")]
public class Player
{
    [Key]
    public long Id { get; set; }

    [InverseProperty("Player1Home")]
    public virtual ICollection<Match> MatchesAsHome1 { get; set; }
}

Of course if I rename HPlayer1Id to Player1HomeId, then Option 2 works correctly again. But the whole purpose of the DataAnnotation is to allow explicit naming when 'Conventions' cannot automatically determine the matching property.

Removing the InverseProperty DataAnnotation on the Player class also seems to fix the issue, but unfortunately I cannot do this because my actual Match class has four Players in it, and thus I need explicit mappings.

And finally, I know I can just use Option 1, but I prefer the consistency of declaring all of my Keys (Primary and Foreign) on the Id fields rather than Foreign Keys on Navigation Properties. And technically, either way is supposed to work.

Is this just a bug in 4.3.1? In EF Code first?

Or is Mapping a ForeignKey AND an InverseProperty from two different properties to a common third property not supported?

Any information would be greatly appreciated!

Update: a second bug?

A third option should work as well (as suggested by Slauma), but causes a NullReferenceException to be thrown the first time I attempt to add an entity to the database. The database never ends up getting created, whereas Option 2 from above does not have this issue. It appears this has worked for Slauma on EF 4.1, but does not for me with EF 4.3.1. (I'm using it with SQL CE 4.0)
[Table("Matches")]
public class Match
{
    [Key]
    public long Id { get; set; }
    [ForeignKey("Player1Home")]
    public long? HPlayer1Id { get; set; }
    [InverseProperty("MatchesAsHome1")]
    public virtual Player Player1Home { get; set; }
}

[Table("Players")]
public class Player
{
    [Key]
    public long Id { get; set; }
    public virtual ICollection<Match> MatchesAsHome1 { get; set; }
}

public class MyContext : DbContext
{
    public DbSet<Match> Matches { get; set; }
    public DbSet<Player> Players { get; set; }
}

Usage:

try
{
    MyContext mc = new MyContext();
    //NullReferenceException gets thrown on the next call
    mc.Matches.Add(new Match());
    mc.SaveChanges();
}
catch (Exception ex)
{
    MessageBox.Show(ex.Message);
}

回答1:


Same behaviour in EF 4.1.

You didn't mention the option to move the InverseProperty attribute to the other side of the relationship:

[Table("Matches")]
public class Match
{
    [Key]
    public long Id { get; set; }

    [ForeignKey("Player1Home")]
    public long? HPlayer1Id { get; set; }

    [InverseProperty("MatchesAsHome1")]
    public virtual Player Player1Home { get; set; }
}

[Table("Players")]
public class Player
{
    [Key]
    public long Id { get; set; }

    public virtual ICollection<Match> MatchesAsHome1 { get; set; }
}

This worked for me and didn't create the extra column.

The behaviour of your option 2 looks like a code-first bug to me.

Edit

Confirming that changing the version from EF 4.1 to EF 4.3.1 causes a NullReferenceException with the model above. The database doesn't get created.




回答2:


This was fixed in EF5 and I've confirmed it still behaves correctly in EF6.

You can see notes of investigation on this issue - https://entityframework.codeplex.com/workitem/138.



来源:https://stackoverflow.com/questions/10020660/why-does-ef-code-first-inverseproperty-attribute-fail-to-work-when-used-with

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!