0

У меня есть следующие модели: Person и Address.EF Navigation Property Not Loading

  • 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 показывает, что все ФКС и ограничения, как и ожидалось. Однако, когда я делаю следующее:

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

Ни один из Person объектов (те, которые имеют адреса) возвращенных не имеют Address или AddressId заселена. Все значение равно null.

Когда я делаю то же самое для db.Address, я получаю все свойства, заполненные, как ожидалось, - действующие отношения в такте. Что вызывает основной конец моего 1: 1 необязательного отношения, чтобы не тянуть зависимые объекты?

Следует отметить, что Мне нужны идентификаторы FK, доступные на обоих объектах, как определено выше.

+0

Использовать свободно или аннотации. Код выглядит хорошо. Должно сработать. – vijayst

ответ

2

Позвольте мне сказать вам, что отношения One-One/Optional не выполняются так. Я использую код, как сделать соотношение 1: 1/0. Также, когда вы используете свободный 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

В скриншоте вы можете увидеть, мы можем Accesss экземпляр адреса от Person экземпляра и лица экземпляр из экземпляра Address из-за сопоставленных отношений.

Вот данные, которые я положил в таблицу.

Tables Data

и здесь структура таблицы

Tables Structure

Person таблицы SQL Script

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 Script

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 доступны на обоих лиц, определенных выше.

Это противоречит соглашению о соотношении 1: 1/0, но лучший способ заключается в следующем.

В отношениях друг к другу значения внешнего ключа и первичных ключей одинаковы, это означает, что если вы получаете доступ к объекту первичного ключа одного объекта, это внешний ключ и первичный ключ другого объекта.

Например, если первичный ключ человека равен 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; } 
}