1

我将 EF5 与 Code First 和 Fluent Mapping Approach 结合使用。这是我的场景,为清楚起见进行了精简:

public class SecuritySettings
{
   public int Id { set; set }
   public Company Company { get; set; }
   public int MaximumInvalidPasswordAttempts { get; set;
   // etc.
}

public class Company
{
   public int Id { set; set }
   public string Name { get; set; }
   public SecuritySettings InternalUserSecuritySettings { get; set; }
   public SecuritySettings ExternalUserSecuritySettings { get; set; }
}

有了上面的内容,我在 Company 表中得到了两个 FK:

   InternalUserSecuritySettings_Id int, null
   ExternalUserSecuritySettings_Id int, null

到现在为止还挺好。

我有用于设置流利映射的配置类 - 一个用于公司,一个用于 SecuritySettings。这些规定了所需的属性。在公司配置中,如果我执行以下操作:

HasRequired(x => x.InternalUserSecurityConfiguration);

这导致:

InternalUserSecuritySettings_Id int,not null ExternalUserSecuritySettings_Id int,null

但是,如果我再添加这个:

HasRequired(x => x.ExternalUserSecurityConfiguration);

我得到以下异常:

在表“Companies”上引入 FOREIGN KEY 约束“FK_dbo.Companies_dbo.SecuritySettings_ExternalUserSecurityConfiguration_Id”可能会导致循环或多个级联路径。指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。

我试过了:

  1. .WithRequiredDependent(y => y.Company).WillCascadeOnDelete(false)
  2. .WithRequiredDependent(y => y.Company).Map(m => m.MapKey("ExternalUSC_Id"))

在其他此类排列中,但要么我得到一个例外,要么只创建了一个 FK。我想在实体配置的流畅映射中执行此操作 - 最好是公司之一。我是否遗漏了一些明显的东西。从非空值如此简单和琐碎的事情到发现很难简单地规定我想要一个密钥,并且两者都不能为空值,这似乎是一种耻辱。

我确实找到了一种通过对实际外键使用单独的属性来使其工作的方法,但首先,对于非空要求来说,这似乎是一项额外的工作,其次,我必须在 OnModelCreating 方法中声明很多配置使用一个“WithMany()”映射,这对我来说是违反直觉的!

4

2 回答 2

0

您可以使用以下流利的方法使其与非空属性一起使用:

        modelBuilder.Entity<Company>().
            HasRequired(x => x.InternalUserSecuritySettings)
            .WithMany()
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<Company>().
            HasRequired(x => x.ExternalUserSecuritySettings)
           .WithMany()
            .WillCascadeOnDelete(false);

生成此数据库:

在此处输入图像描述

但是 - 我有点担心您实体的Company财产。SecuritySettings您是否希望该导航属性映射到内部/外部SecuritySettings属性的另一端?如果是这样 - 这不能通过 EF 完成(您不能在一个实体上拥有一个属性,映射到其他 2 个属性)。考虑原因:如果您将 a 添加CompanySecuritySetting-

var CompanyA = new Company;
CompanyA.SecuritySettings(new SecuritySettings());

它应该映射到实体的哪一端SecuritySettings(内部或外部?)因为无法通过上面的场景来判断它是无效的。

您可以将 2 个不同SecuritySettings的集合添加到您的公司,然后您将有一个正确的映射。

于 2013-03-01T12:39:33.060 回答
0

RE:Mark Oreta - 当我查看源代码控制历史时,公司财产最初并不存在 - 它一定是我的“让我们试试这个,看看会发生什么”的尝试之一!我已经删除了这个,因为我不需要在公司环境中引用安全设置。我确实有一个与你类似的版本,但我把你的作为答案,因为我能够从你的答案中引导至少能够在我的 CompanyConfiguration 类中添加所有映射,而不是在 OnModelCreating 方法中. 现在唯一的痛点是这些仍然是一对一的映射,WithMany() 不会推断或强制执行。因此,我可以强制执行此操作的唯一方法是使用独特的约束。不是很漂亮!感谢您的时间和回答。

编辑:

只是为了分享我对这个问题的当前版本的答案:

  1. 公司配置类(DataEntityBaseConfiguration 继承自 EntityTypeConfiguration)
public class CompanyConfiguration : DataEntityBaseConfiguration<Company>
   {
    public CompanyConfiguration()
    {
        Property(x => x.Name).IsRequired();
        Property(x => x.Name).HasMaxLength(256);
        HasRequired(x => x.InternalUserSecurityConfiguration).WithMany().WillCascadeOnDelete(false);
        HasRequired(x => x.ExternalUserSecurityConfiguration).WithMany().WillCascadeOnDelete(false);

    }
   }

然后,在我的 Context Initialiser 类中,我添加以下代码行来对两个属性强制执行唯一约束:

AddUniqueConstraint<Company>(() => new Company().ExternalUserSecurityConfigurationId);
AddUniqueConstraint<Company>(() => new Company().InternalUserSecurityConfigurationId);

AddUniqueConstraint 是我编写的用于执行 sql 以创建唯一约束的方法 -请点击此处阅读更多信息。

于 2013-03-01T13:15:01.717 回答