为什么在与[ForeignKey]属性一起使用时,EF Code First [InverseProperty]属性无法正常工作? [英] Why does EF Code First [InverseProperty] attribute fail to work when used with [ForeignKey] attribute?

查看:1850
本文介绍了为什么在与[ForeignKey]属性一起使用时,EF Code First [InverseProperty]属性无法正常工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用:EF 4.3.1,Visual Studio 2010,SQL CE 4.0



我的理解是,在使用DataAnnotation声明外键EF,可以通过以下方法之一完成:



选项1 -

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

public virtual Player Player1Home {get;组;

选项2 -

  public long? HPlayer1Id {get;组; } 

[ForeignKey(HPlayer1Id)]
public virtual Player Player1Home {get;组;问题:当InverseProperty DataAnnotation与选项一起使用时,

2除了HPlayer1Id之外,还会在数据库(Player1Home_Id)中生成一个额外的列。

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

// - 选项1 - 这个工作很棒 - //
public long? HPlayer1Id {get;组; }
[ForeignKey(HPlayer1Id)]
public virtual Player Player1Home {get;组; }

// - 选项2 - 这不工作,它在数据库中生成一个额外的列 - //
[ForeignKey(Player1Home)]
public长? HPlayer1Id {get;组; }
public virtual Player Player1Home {get;组; }
}

[表(玩家)]
public class Player
{
[Key]
public long Id {get ;组; }

[InverseProperty(Player1Home)]
public virtual ICollection< Match> MatchesAsHome1 {get;组;当然,如果我将HPlayer1Id重命名为Player1HomeId,则选项2再次正确工作。 。但是DataAnnotation的全部目的是允许在约定不能自动确定匹配属性时显式命名。



删除Player类上的InverseProperty DataAnnotation似乎也会修复这个问题,但不幸的是我不能这样做,因为我的实际的Match类有四个玩家,因此我需要明确的映射。



最后,我知道我可以使用选项1,但我更喜欢在Id字段上声明我的所有键(主要和外部)的一致性,而不是导航属性上的外键。在技​​术上,任何一种方式都应该工作。



这是4.3.1中的一个错误吗?在EF代码中首先?



还是将两个不同属性的ForeignKey和一个InverseProperty映射到不支持的常见第三个属性?



任何信息将不胜感激!



更新:第二个错误?/ / H2>
第三个选项应该是(如Slauma所建议的),但是当我第一次尝试向数据库添加实体时,会引发NullReferenceException。数据库永远不会被创建,而上面的选项2没有这个问题。看来这对于EF 4.1的Slauma有效,但是对于EF 4.3.1而言并不适用。 (我使用SQL CE 4.0)

  [Table(Matches)] 
public class Match
{
[Key]
public long Id {get;组; }
[ForeignKey(Player1Home)]
public long? HPlayer1Id {get;组; }
[InverseProperty(MatchesAsHome1)]
public virtual Player Player1Home {get;组; }
}

[表(玩家)]
public class Player
{
[Key]
public long Id {get ;组; }
public virtual ICollection< Match> MatchesAsHome1 {get;组; }
}

public class MyContext:DbContext
{
public DbSet< Match>比赛{get;组; }
public DbSet< Player>玩家{get;组; }
}

用法:

  try 
{
MyContext mc = new MyContext();
// NullReferenceException在下一次调用时抛出
mc.Matches.Add(new Match());
mc.SaveChanges();
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}


解决方案

EF 4.1中的相同行为。



您没有提到将 InverseProperty 属性移动到关系另一边的选项: p>

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

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

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

[表(玩家)]
public class Player
{
[Key]
public long Id {get ;组; }

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

这对我有效,没有创建额外的列。 p>

您的选项2的行为看起来像我的代码第一个错误。



编辑



确认将版本从EF 4.1更改为EF 4.3.1会导致上述模型导致 NullReferenceException 。数据库未创建。


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

解决方案

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.

这篇关于为什么在与[ForeignKey]属性一起使用时,EF Code First [InverseProperty]属性无法正常工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆