0

我有以下型号 - PersonAddressEF导航属性不加载

  • Person未经Address
  • Address总是属于Person

类可以存在:

public class Person {  
     // properties 

     [ForeignKey("Address")] 
     public int? AddressId { get; set; } 
     public virtual Address Address { get; set; } 
} 

public class Address { 
     // properties 

     [ForeignKey("Person")] 
     public int PersonId { get; set; } 
     public virtual Person Person { get; set; } 
} 

PersonConfiguration

HasOptional(a => a.Address) 
       .WithMany() 
       .HasForeignKey(u => u.AddressId); 

AddressConfiguration

HasRequired(a => a.Person) 
      .WithMany() 
      .HasForeignKey(u => u.PersonId); 

问题

SSMS示出了所有FKS和约束是按预期方式。然而,当我做到以下几点:

var dbPerson = db.Persons.Include(s => s.Address).ToList(); 

返回Person对象(那些有地址)都没有填充AddressAddressId。一切都是空的。

当我对db.Address执行相同的操作时,我得到的所有属性都按预期方式填充 - 有效的关系触发。是什么导致我的1:1可选关系的主体结束不拉入相关实体?

我应该注意,我确实需要FK ID在上面定义的上定义的两个实体上。

+0

使用流利或注释。代码看起来没问题。应该管用。 – vijayst

回答

2

让我告诉你,One-One/Optional关系不是这样的。我分享代码如何使1:1/0关系。 另外,当您使用流畅的API时,不需要使用数据注解属性。只使用其中的一个,流利的API更好,因为关系看起来很清楚。

在1:1/0的关系中,外键没有单独定义。外键仅在任何一个表中定义,并且一个实体的主键变为另一个相关实体的主键和外键。在这个例子中,我将Id字段作为Person实体(表)的主键,并将Id作为Address实体(表)的主键和外键。这是1:1/0关系的正确方法。如果我们不遵循这个惯例,那么这种关系就没有做好,并且会面临问题。

下面是代码

public class Person 
{ 
    // properties 
    public int Id { get; set; } 
    public string Name { get; set; } 

    public virtual Address Address { get; set; } 
} 

public class Address 
{ 
    // properties 
    public int Id { get; set; } 
    public string Location { get; set; } 

    public virtual Person Person { get; set; } 
} 

public class PersonConfiguration : EntityTypeConfiguration<Person> 
{ 
    public PersonConfiguration() 
    { 
     ToTable("Person"); 
     HasKey(p => p.Id); 

    } 
} 

public class AddressConfiguration : EntityTypeConfiguration<Address> 
{ 
    public AddressConfiguration() 
    { 
     ToTable("Address"); 
     HasKey(p => p.Id); 
     Property(a => a.Id).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None); 

     HasRequired(p => p.Person) 
      .WithOptional(a => a.Address); 
    } 
} 

public class AppObjectContext : DbContext 
{ 
    public AppObjectContext() : base("AppConnectionString") 
    { 

    } 

    public DbSet<Person> People { get; set; } 
    public DbSet<Address> Addresses { get; set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     base.OnModelCreating(modelBuilder); 

     modelBuilder.Configurations.Add(new PersonConfiguration()); 
     modelBuilder.Configurations.Add(new AddressConfiguration()); 
    } 
} 

这里为结果的截图

Results

在截图中,你可以看到,我们可以从Person实例和个人accesss Address实例来自Address实例的实例,因为映射关系。

这里是我把数据放在表中。

Tables Data

这里是表结构

Tables Structure

Person表SQL脚本

CREATE TABLE [dbo].[Person](
    [Id] [int] IDENTITY(1,1) NOT NULL, 
    [Name] [nvarchar](max) NULL, 
CONSTRAINT [PK_dbo.Person] PRIMARY KEY CLUSTERED 
(
    [Id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] 

GO 

地址表SQL脚本

CREATE TABLE [dbo].[Address](
    [Id] [int] NOT NULL, 
    [Location] [nvarchar](max) NULL, 
CONSTRAINT [PK_dbo.Address] PRIMARY KEY CLUSTERED 
(
    [Id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] 

GO 

ALTER TABLE [dbo].[Address] WITH CHECK ADD CONSTRAINT [FK_dbo.Address_dbo.Person_Id] FOREIGN KEY([Id]) 
REFERENCES [dbo].[Person] ([Id]) 
GO 

ALTER TABLE [dbo].[Address] CHECK CONSTRAINT [FK_dbo.Address_dbo.Person_Id] 
GO 

在回答您注意:

我要指出,我确实需要FK的ID在两个实体 上面定义的访问。

它违背了1:1/0关系的约定,但更好的方法如下。

在一对一关系中,外键和主键值是相同的,也就是说,如果你访问一个实体的主键实体,它也是另一个实体的外键和主键。

例如,如果person的主键是20,那么映射到这个人的地址的外键和主键也是20.这是正确的访问方式。

-1
class Program 
{ 
    static void Main(string[] args) 
    { 
     using (var db = new NavigationContext()) 
     { 
      Console.Write("Enter address: "); 
      var addr = Console.ReadLine(); 

      Console.Write("Enter person: "); 
      var prs = Console.ReadLine(); 

      Address address = new Address { Name = addr }; 
      db.Addresses.Add(address); 

      Person person = new Person { Name = prs, AddressID = address.AddressID }; 
      db.Persons.Add(person); 
      db.SaveChanges(); 

      Console.WriteLine("Press any key to exit..."); 
      Console.ReadKey(); 
     } 
    } 
} 


[Table("Person")] 
public class Person 
{ 
    [Key] 
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)] 
    public int PersonID { get; set; } 
    public string Name { get; set; } 
    public int? AddressID { get; set; } 
    //[ForeignKey("AddressID")] 
    //public virtual Address Address { get; set; } 
} 

[Table("Address")] 
public class Address 
{ 
    [Key] 
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)] 
    public int AddressID { get; set; } 
    public string Name { get; set; } 
    public int PersonID { get; set; } 
    [ForeignKey("PersonID")] 
    public virtual Person Person { get; set; } 
} 



public class NavigationContext : DbContext 
{ 
    public NavigationContext() 
     : base("SQLDBConnection") 
    { 

    } 
    public DbSet<Person> Persons { get; set; } 
    public DbSet<Address> Addresses { get; set; } 
}