【问题标题】:EF6 Code First: Using Fluent API to declare a Foreign KeyEF6 Code First:使用 Fluent API 声明外键
【发布时间】:2014-01-16 03:45:48
【问题描述】:

我正在使用 EF 6 和 Code First 开发与保险行业相关的应用程序。对于这个应用程序,每个账户可以有多个策略,每个策略可以有多个事务。此外,每个帐户都必须与身份(姓名、地址、城市等)有关系。 Policy 也与 Identity 有关系,但它是可选的。

由于 Account -> Identity and Account ->> Policy -> Identity,我发现我需要使用 Fluent API 将其中至少一条路径的 WillCascadeDelete 设置为 False。

我的问题是如何将 Account.IdentityId 和 Policy.InsuredIdentityId 属性配置为外键?我已经避免将任何导航/外键字段添加到身份类,因为永远不应该有从一个身份导航到另一个类的理由。这就是我很难弄清楚这一点的原因吗?

public class Account
{
    public long Id { get; set; }
    public long IdentityId { get; set; }
    public virtual Identity Identity { get; set; }

    public ICollection<Policy> Policies { get; set; }
}

public class Policy
{
    public long Id { get; set; }

    public long AccountId { get; set; }
    public virtual Account Account { get; set; }

    public bool UseAccountIdentity { get; set; }
    public long InsuredIdentityId { get; set; }
    public virtual Identity InsuredIdentity { get; set; }
}

 public class Identity 
{        
    public long Id { get; set; }

    public string Name { get; set; }
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Zip { get; set; }
}

public class AccountConfiguration : EntityTypeConfiguration<Account>
{
    public AccountConfiguration()
    {
        HasRequired(a => a.Identity).WithOptional(x => x.Account).WillCascadeOnDelete(false);
        HasMany(a => a.Policies).WithRequired(p => p.Account).HasForeignKey(p => p.AccountId);
    }
}

public class PolicyConfiguration : EntityTypeConfiguration<Policy>
{
    public PolicyConfiguration()
    {
        HasOptional(p => p.InsuredIdentity).WithOptionalPrincipal().WillCascadeOnDelete(false);
    }
}

作为一个附带问题,EF Code First 是否有任何好的书籍或其他参考资料?我有 Julia Lerman 的 Programming Entity Framework: Code First,这对于它所涵盖的示例来说很好,但它没有涵盖足够的案例。

【问题讨论】:

    标签: c# entity-framework ef-code-first


    【解决方案1】:

    首先,public ICollection&lt;Policy&gt; Policies { get; set; } 应该是public virtual ICollection&lt;Policy&gt; Policies { get; set; }

    只有当关系的一侧是一,而另一侧是多时,才能映射 EF 外键属性。任何时候你有一个 1:1 或 1:0..1 的关系,从属实体将采用与主体相同的主键。在这些情况下,不能有外键,因为依赖的外键是它的主键。

    所以对于这个:

    HasRequired(a => a.Identity).WithOptional(x => x.Account)
    

    ... 帐户的 ID 将与身份的 ID 相同。这意味着,您可以从 Account 实体中完全删除 IdentityId 属性。但是我不明白该代码是如何编译的,因为Identity 没有Account 导航属性..?

    当涉及到您的策略映射时,这真的是您想要的吗?您说 Policy 可以与 Identity 具有可选关系,但是您这样做的方式:

    HasOptional(p => p.InsuredIdentity).WithOptionalPrincipal()
    

    ...表示Identity 只能关联(直接)做一个Policy。使映射看起来像这样有什么问题?

    HasOptional(p => p.InsuredIdentity).WithMany()
        .HasForeignKey(x => x.InsuredIdentityId)
        .WillCascadeOnDelete(false);
    

    使用上述内容,您仍然没有从IdentityPolicy 的任何导航属性。你不需要一个,你可以调用.WithMany() 作为一个无参数。但是,这会告诉数据库将Identity 设置为主体,将Policy 设置为从属,因此您在数据库中有正常的fk 关系,您仍然无法从Identity 导航到Policy代码。

    其他cmets:

    策略也与身份有关系,但它是可选的。

    这意味着Policy.InsuredIdentityId 应该是System.Nullable&lt;long&gt;

    【讨论】:

    • 不完全是我想要完成的,但我认为这让我走上了正确的道路。
    • 我确信这是一个复杂的域,并且可能有几种不同的建模方法。请注意,您始终可以在 EF 模型中将事物设为零或一对多以启用 fk 属性,而只需省略任一侧的导航属性以实现单向关系。但是,只要您拥有真正的 1:1 或 1:0..1,您确实希望它们共享相同的主键,在这种情况下,外键没有意义。
    【解决方案2】:

    我的问题是概念性的。虽然通常身份仅适用于一个帐户(导致我将其可视化为 1:1),但理论上身份可以多次使用,因此可以在多个帐户上使用。如果我使用以下配置,我会得到我想要的。然后由我来执行任何规则,例如身份只能用于一个帐户(但需要尽可能多的策略)

    public class IdentityConfiguration : EntityTypeConfiguration<Identity>
    {
        public IdentityConfiguration()
        {
            HasMany(i => i.Accounts).WithRequired(i => i.Identity).HasForeignKey(a => a.IdentityId);            
        }
    }
    

    或者,我可以将身份设置为主要实体,将帐户设置为可选的依赖项。这会起作用,因为所有帐户都有一个身份,但并非所有身份都链接到一个帐户。帐户将不再拥有自己的密钥。

    这不直观,这有点令人担忧。

    【讨论】:

    • 保险没有什么是直观的。
    • 无法反驳。我花了几分钟来整理一下我的想法,但倾向于将 Identity 作为与 Account 1:1 的主要实体。谢谢。
    • 记住是 1:1,你必须在同一个事务中创建和删除两者。你不能创建一个,保存它,然后链接另一个。
    • 不是只有两端都需要的情况吗?在我的例子中,没有身份就无法创建帐户,但可以在没有帐户的情况下创建身份,即用于策略。
    • 好的,那么我们在这里只讨论语义。我称之为 1:0..1(一对​​零或一)。您是对的,您可以将其设为可选的一端并延迟创建所需的一侧。
    猜你喜欢
    • 2013-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-20
    相关资源
    最近更新 更多