简体   繁体   English

EF导航属性未加载

[英]EF Navigation Property Not Loading

I have the following models - Person and Address . 我有以下模型- PersonAddress

  • A Person can exist without a Address 一个Person可以没有Address而存在
  • A Address always belongs to a Person Address始终属于一个Person

Classes: 类别:

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);

Problem 问题

SSMS shows that all FKs and constraints are as expected. SSMS显示所有FK和约束均符合预期。 However when I do the following: 但是,当我执行以下操作时:

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

None of the Person objects (ones that have Addresses) returned have Address or AddressId populated. 返回的Person对象(具有Addresses的对象) AddressId填充AddressAddressId Everything is null. 一切都为空。

When I do the same for db.Address , I get all properties populated as expected - valid relations in-tact. 当我对db.Address进行相同db.Address ,我将按预期填充所有属性-完整的有效关系。 What is causing the principal end of my 1:1 optional relationship to not pull in the dependent entities? 是什么导致我的1:1可选关系的主要结束不提取从属实体?

I should note that I do need FK IDs accessible on both entities as defined above . 我应该注意, 我确实需要在上述两个实体上都可以访问的FK ID

Let me tell you that the One-One/Optional relationship is not made like this. 让我告诉您,并非是这样的一对一/可选关系。 I am sharing the code how to make 1:1/0 relationship. 我正在分享代码,以建立1:1/0关系。 Also, when you are using fluent API, no need to use Data Annotation attributes. 另外,当您使用流畅的API时,无需使用数据注释属性。 Use only one of them and fluent API is better, because relationship looks very clear. 仅使用其中之一,流利的API更好,因为关系看起来很清晰。

In 1:1/0 relationship, the foreign keys are not defined separately. 在1:1/0关系中,未单独定义外键。 Foreign key is defined in any one table only, and the primary key of one entity becomes primary key and foreign key of another related entity. 外键仅在任何一个表中定义,一个实体的主键成为另一相关实体的主键和外键。 In this example, I made Id field as primary key of Person entity(table) and made the Id as primary key and foreign key of Address entity(table). 在此示例中,我将ID字段用作Person实体(表)的主键,并将ID用作Address实体(表)的主键和外键。 This is the proper way of 1:1/0 relationship. 这是1:1/0关系的正确方法。 If we don't follow this convention, the relationship is not made properly and face problems. 如果我们不遵守这一约定,则这种关系将无法正确建立并面临问题。

Here is the code 这是代码

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());
    }
}

and here is the resultant screenshot 这是结果截图

结果

In screenshot you can see, we can accesss Address instance from Person instance and Person instance from Address instance due to mapped relationship. 在屏幕快照中,您可以看到,由于映射关系,我们可以从Person实例访问Address实例,并从Address实例访问Person实例。

Here is data which I put in table. 这是我放在表中的数据。

表格数据

and here is tables structure 这是表格结构

表结构

Person table SQL Script 人员表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

Address Table SQL Script 地址表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

In response to your Note: 针对您的注意事项:

I should note that I do need FK IDs accessible on both entities as defined above. 我应该注意,我确实需要如上所述在两个实体上都可以访问的FK ID。

It is against convention of 1:1/0 relationship, but the better way is as follows. 它违反了1:1/0关系的约定,但是更好的方法如下。

In one to one relationship, the foreign key and primary keys values are same, it means, if you access the primary key entity of one entity, it is the foreign key and primary key of another entity as well. 在一对一关系中,外键和主键的值相同,这意味着,如果访问一个实体的主键实体,则它也是另一实体的外键和主键。

For example, if the primary key of person is 20, then the foreign key and primary key of address mapped with this person is also 20. This is the proper way of accessing. 例如,如果人员的主键为20,则与该人员映射的地址的外键和主键也为20。这是正确的访问方式。

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; }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM