EF导航属性未加载

时间:2016-08-15 05:08:57

标签: c# entity-framework entity-framework-4 entity entity-framework-5

我有以下模型 - PersonAddress

  • 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显示所有FK和约束都符合预期。但是,当我执行以下操作时:

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

所有Person个对象(具有地址的对象)都没有填充AddressAddressId。一切都是空的。

当我为db.Address执行相同操作时,我会按预期填充所有属性 - 有效关系。是什么导致我的1:1可选关系的主要结束不拉入从属实体?

我应该注意我确实需要在上面定义的两个实体上都可以访问FK ID

1 个答案:

答案 0 :(得分:3)

让我告诉你,One-One / Optional关系不是这样的。我正在分享如何建立1:1/0关系的代码。 此外,当您使用Fluent API时,无需使用Data Annotation属性。只使用其中一种,流畅的API更好,因为关系看起来很清楚。

在1:1/0关系中,外键未单独定义。外键仅在任何一个表中定义,并且一个实体的主键成为另一个相关实体的主键和外键。在这个例子中,我将Id字段作为Person实体(表)的主键,并将Id作为地址实体(表)的主键和外键。这是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实例访问Address实例,从Address实例访问Person实例。

以下是我放在表格中的数据。

Tables Data

,这是表格结构

Tables Structure

人员表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.这是正确的访问方式。