首先了解实体框架代码中的ForeignKey属性

时间:2014-02-18 14:05:50

标签: c# entity-framework foreign-keys code-first shared-primary-key

有关背景信息,请参阅以下文章:

Entity framework one to zero or one relationship without navigation property

我一直认为ForeignKey用于显示类中哪个属性持有确定导航属性的ForeignKey,例如。

public class MemberDataSet
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public int? DeferredDataId { get; set; }
    [ForeignKey("DeferredDataId")]
    public virtual DeferredData DeferredData { get; set; }
}

但是,我在链接的帖子上发现这是不对的,因为DeferredData的主键被称为Id我实际需要:

public class MemberDataSet
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public int? DeferredDataId { get; set; }
    [ForeignKey("Id")]
    public virtual DeferredData DeferredData { get; set; }
}

即。 ForeignKey用于指向另一个类。

然后我继续改变其他一些参考文献:

public class MemberDataSet
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public int? DeferredDataId { get; set; }
    [ForeignKey("Id")]
    public virtual DeferredData DeferredData { get; set; }

    public int? SignedOffById { get; set; }
    [ForeignKey("UserId")]
    public virtual UserProfile SignedOffBy { get; set; }
}

然而,这失败了。关于这一点,ForeignKey需要指向MemberDataSet类的ID。

public class MemberDataSet
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public int? DeferredDataId { get; set; }
    [ForeignKey("Id")]
    public virtual DeferredData DeferredData { get; set; }

    public int? SignedOffById { get; set; }
    [ForeignKey("SignedOffById")]
    public virtual UserProfile SignedOffBy { get; set; }
}

我认为这是因为这第二个关系是一对多,而第一个关系是一对零或一,有效的关系的主要结束不同,但我希望对此有一些清晰/对好文章的引用,所以我可以理解正在发生的事情以及ForeignKey正在做的事情。

我也在寻找上面例子中public int? DeferredDataId { get; set; }如何适应等式的清晰度,因为它没有明确地链接到DeferredData。我很高兴这将符合惯例,但我如何明确告诉它,例如如果它有不同的名字?我在这个关于使用ForeignKey属性的讨论中看到过的例子,但这并不是所有情况下的答案!

所有帮助都非常感激 - 希望了解问题而不是修复特定问题,因为我在模型中有很多引用,因此需要确定采用每种方法的方法。

感谢。

修改

添加了其他类来提供帮助:

public class DeferredData
{

    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    //other properties
}

public class UserProfile
{

    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }

    //other properties
}

3 个答案:

答案 0 :(得分:26)

1..0关系MemberDataSet的所需方面不应具有DeferredData的FK。相反,DeferredData的PK也应该是MemberDataSet的FK(称为共享主键)

public class MemberDataSet
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public virtual DeferredData DeferredData { get; set; }
}

public class DeferredData
{
    // DeferredData.Id is both the PK and a FK to MemberDataSet
    [Key]
    [DatabaseGenerated( DatabaseGeneratedOption.None )]
    [ForeignKey( "MemberDataSet" )]
    public int Id { get; set; }

    [Required]
    public virtual MemberDataSet MemberDataSet { get; set; }
}

Fluent API:

modelBuilder.Entity<MemberDataSet>()
    .HasOptional( mds => mds.DeferredData )
    .WithRequired()
    .WillCascadeOnDelete();

答案 1 :(得分:0)

我认为你是对的(前提是我理解你的权利)。 [ForeignKeyAttribute]用于相应的外键。不在链接对象的主键上。

This is my object, and the foreign key is DeferredDataId

对象中的Id都不是外键(它的主键),链接对象的ID也不是外键(它是关系另一端的主键)

希望我理解正确:)因为我不确定。

答案 2 :(得分:0)

我认为你原来的想法是正确的,只有一个例外。通过将外键放在MemberDataSet上,您暗示您希望与零或一对多的关系。

在您的示例中,MemberDataSet.DeferredData是可选的,许多DeferredData个实例可以引用MemberDataSet

用流利的语法表示:

modelBuilder.Entity<MemberDataSet>()
    .HasOptional(dataSet => dataSet.DeferredData)
    .WithMany()
    .HasForeignKey(deferredData => deferredData.DeferredDataId);

为了使它成为一对一或零的属性,您可以在MemberDataSet的DeferredDataId列上放置唯一(非空)键约束。这意味着DeferredData实体只能由单个MemberDataSet实体引用。

CREATE UNIQUE INDEX unique_MemberDataSet_DeferredDataId ON MemberDataSet(DeferredDataId) WHERE DeferredDataId IS NOT NULL

注意:This type of filtered key is only available in SQL Server 2008 and up.

相关问题