【问题标题】:Code First Optional One-To-One RelationshipCode First 可选的一对一关系
【发布时间】:2015-01-25 14:13:05
【问题描述】:

为我有两个客户和用户表的情况编写模型。每个用户记录可能有一个可选的相关客户记录,反之亦然,但它们都不是必须的。我发现FK Associations 不是我需要的,但Independent Associations 是。但我只能找到一种让它工作的方法,我不断收到“无法确定主体端......这个关联的主体端必须使用关系流式 API 或数据注释显式配置。”例外。

我的模型很简单:

public class User
{
    [Key]
    public int          Id              { get; set; }
    [StringLength(20)]
    public string       CustomerId      { get; set; }
    public string       Password        { get; set; }
    public bool         Locked          { get; set; }

    //[ForeignKey("CustomerId")]
    public virtual Customer Customer    { get; set; }
}

public class Customer
{
    [Key]
    [Column("Id", TypeName = "nvarchar")]
    [StringLength(20)]
    public string       Id              { get; set; }   //  nvarchar    20
    [Required]
    public string       GivenName       { get; set; }   //  nvarchar    100
    [Required]
    public string       Surname         { get; set; }   //  nvarchar    100

    //[InverseProperty("Customer")]
    public virtual User User            { get; set; }
}

我尝试添加 ForeignKeyAttribute 和 InversePropertyAttribute,它们目前已被注释掉,但它们也没有帮助。如果可能的话,我更喜欢使用数据注释而不是流畅的 API。

【问题讨论】:

  • 你想依赖延迟加载,对吗?你看过这篇文章吗:stackoverflow.com/questions/12606948/…
  • @DDiVita 是的,延迟加载,是的,我已经看到了这个问题,但是问题是 Principal 有一个 RequiredAttribute,在我的情况下,用户记录可以在没有客户记录的情况下存在。
  • @DDiVita 我已经尝试使用RequiredAttribute,正如答案所暗示的那样,但EF找不到Customer_ID,然后我添加了ForeignKeyAttribute并收到了这个异常:\tSystem.Data.Entity .Edm.EdmAssociationEnd: : 多重性在关系“User_Customer”中的角色“User_Customer_Source”中无效。因为从属角色属性不是关键属性,所以从属角色的多重性的上限必须是“*”。

标签: c# asp.net-mvc entity-framework ef-code-first data-annotations


【解决方案1】:

一对一关系中,一端必须是主体,而另一端必须是从属Principal end 是最先插入的,并且可以在没有依赖的情况下存在。 Dependent 端是必须插入主体之后的端,因为它具有主体的外键。在配置一对一关系时,Entity Framework 要求依赖的主键也是外键。这个问题最容易解决,方法是在依赖类上使用ForeignKey 注解来标识它包含外键.在您的情况下,Customer 可能是依赖项,它的键 Customer.UserId 也应该是外键。但是两个 Key 必须使用相同的类型声明:

public class User
{
   [Key]
   public int  Id  { get; set; }

   public virtual Customer Customer { get; set; }
}

public class Customer
{
   [Key, ForeignKey("User")]
   public int  UserId { get; set; }

   public virtual User User{ get; set; } 
}

我不知道如何使用Data Annotations解决您的问题,但是如果您想使用Fluent Api,我认为关系的配置是这样的:

 modelBuilder.Entity<User>().HasOptional(u => u.Customer).WithOptionalPrincipal(c => c.User);

更新

我了解您的情况,但如果您的列与模型中显示的列相同,我认为您应该在 DB 中映射一对多关系,而不是一对一。尝试以这种方式映射您的关系:

public class User
{
    [Key]
    public int Id { get; set; }

    public string Password { get; set; }
    public bool Locked { get; set; }

    public string CustomerId { get; set; }

    [ForeignKey("CustomerId")]
    public virtual Customer Customer { get; set; }
}

public class Customer
{
    [Key]
    [Column("Id", TypeName = "nvarchar")]
    [StringLength(20)]
    public string Id { get; set; }   //  nvarchar    20
    [Required]
    public string GivenName { get; set; }   //  nvarchar    100
    [Required]
    public string Surname { get; set; }   //  nvarchar    100

    public virtual  ICollection<User> Users { get; set; }
}

请记住将您的属性映射到与 DB 中相同的列名称。

【讨论】:

  • 谢谢,我希望可以使用Data Annotations 解决这个问题。此外,我不希望这两个表共享相同的 PK。
  • 我已尝试按照您的建议添加配置,但我收到了 SqlException 0x80131904 列名“User_Id”无效。列名“User_Id”无效。这很奇怪,因为我用KeyAttribute 标记了Id。抛出此异常的行是var user = users.Where(s =&gt; s.CustomerId.Equals(CustomerId)).FirstOrDefault();users 定义为var users = from u in db.Users select u;
  • 你在尝试哪一个?。如果您尝试了第二个,则 User 中的属性 CustomerId 未映射为 FK,因此它的值始终为 null。我试过这个查询 var user = users.FirstOrDefault(s => s.Customer != null && s.Customer.Id.Equals(CustomerId));它奏效了。您在测试此模型配置之前删除了数据库吗?在 Context 的构造函数中添加: Database.SetInitializer(new DropCreateDatabaseIfModelChanges() );
  • 我也尝试过使用modelBuilder.Entity&lt;Customer&gt;().HasOptional(c =&gt; c.User).WithOptionalPrincipal(u =&gt; u.Customer).Map(x =&gt; x.MapKey("CustomerId"));,但它给了我MetadataException 指定的架构无效。错误:(12,6):错误 0019:类型中的每个属性名称必须是唯一的。已定义属性名称“CustomerId”。
  • 是的,我说的是第二个,第一个共享PK,这在我的情况下不是一个选项。如果我将 CustomerId 映射为 FK,我会得到此 ModelValidationException:在模型生成期间检测到一个或多个验证错误:\tSystem.Data.Entity.Edm.EdmAssociationEnd: : Multiplicity 在关系“Customer_User”中的角色“Customer_User_Target”中无效。因为从属角色属性不是关键属性,所以从属角色的多重性的上限必须是“*”。为什么要删除数据库?我的数据库中有真实数据的副本。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-26
  • 2016-01-27
  • 1970-01-01
  • 1970-01-01
  • 2016-06-01
相关资源
最近更新 更多