2012-05-24 1 views
2

У меня есть следующие C# Entity Framework код Первые объекты, определенные:Code First - внешний ключ Ссылка не загружая о назначении Id

class Program 
{ 
    static void Main(string[] args) 

    { 
     var context = new MyContext(); 

     var person = new Person 
     { 
      FirstName = "Nadege", 
        LastName = "Deroussen", 
        BirthDate = DateTime.Now, 
        AccessCode = new AccessCode { Code = "ABC" } 
     }; 
     context.Persons.Add(person); 

     var accessCode = new AccessCode { Code = "MGH" }; 
     context.AccessCodes.Add(accessCode); 
     context.SaveChanges(); 


     var person = context.Persons.Where(e => e.Id == 1).Single();    
     person.AccessCodeId = 2; 

     context.SaveChanges(); 

     Console.Write("Person saved !"); 
     Console.ReadLine(); 
    } 
} 

public class Person 
{ 
    public int Id { get; set; } 
    public string LastName { get; set; } 
    public string FirstName { get; set; } 
    public DateTime BirthDate { get; set; } 


    public int AccessCodeId { get; set; } 
    [ForeignKey("AccessCodeId")] 
    public virtual AccessCode AccessCode { get; set; } 
} 

public class AccessCode 
{ 
    public int Id { get; set; } 
    public string Code { get; set; } 
} 

public class MyContext : DbContext 
{ 
    public DbSet<Person> Persons { get; set; } 
    public DbSet<AccessCode> AccessCodes { get; set; } 
} 

В методе Main, после назначения AccessCodeId = 2, если я проверить AccessCode ссылку в человек, он все еще указывает на AccessCode с Id == 1. Как я могу получить это авто-обновление?

Я изучаю EF, поэтому, пожалуйста, извините меня, если это не имеет смысла.

+0

Имеют ли лица и AccessCodes наборы генерировать свою собственную идентичность? –

+0

У человека есть 2 объекта: AccessCode и AccessCodeId. Вам не нужен AccessCodeId в Person, потому что у вас есть AccessCode.Id, доступный из Person. Удалите это свойство и EF автоматически создаст взаимосвязь между Person и AccessCodes. Теперь не отображается изменение, потому что вы устанавливаете одно свойство и получаете другое другое, поэтому будьте осторожны. –

+0

@daveL Поскольку оба объекта имеют свойство Id, EF автоматически делает их первичным ключом. –

ответ

2

Наконец я получил ожидаемое поведение со следующим кодом:

namespace ConsoleApplication2 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Database.SetInitializer<TestContext>(new DropCreateDatabaseAlways<TestContext>()); 
      var context = new TestContext(); 
      var child = new Child { }; 
      var parent = new Parent { Child = child }; 
      context.Parents.Add(parent); 
      context.Children.Add(new Child { }); 

      context.SaveChanges(); 

      context.Parents.First().ChildId = 2; 
      context.SaveChanges(); 
     } 
    } 

    public class Parent 
    { 
     public int Id { get; set; } 
     public virtual int ChildId { get; set; } 
     public virtual Child Child { get; set; } 
    } 
    public class Child 
    { 
     public int Id { get; set; } 
    } 
    public class TestContext : DbContext 
    { 
     public DbSet<Parent> Parents { get; set; } 
     public DbSet<Child> Children { get; set; } 
    } 
} 

Изображение показывает сеанс отладки, в том, что только после назначения ChildId (до SaveChanges() называется), свойство Ребенок также получает правильно обновлено. Спасибо всем, кто внес свои ценные предложения.

enter image description here

1

Ну, я не согласен с @ Давидом. Сначала код, база данных First или Model First - это просто разные методы для достижения одной и той же цели. И Code First с аннотациями данных или Fluent API очень эффективен. Вам просто нужно научиться его использовать.

Ваш код будет работать. В первую очередь удалите [ForeignKey("AccessCodeId")]. Это избыточно, и вы все равно помещали его в неправильное свойство. Код Сначала установит AccessCodeId как внешний ключ Соглашение. AccessCode - свойство навигации, не будет генерироваться в базе данных, и только здесь, чтобы сделать вашу жизнь проще. Для получения дополнительной информации прочитайте эту статью: Code First Conventions.

Вот рабочий код (который я тестировал):

public class Person 
{ 
    public int Id { get; set; } 
    public string LastName { get; set; } 
    public string FirstName { get; set; } 
    public DateTime BirthDate { get; set; } 

    public int AccessCodeId { get; set; } 
    public virtual AccessCode AccessCode { get; set; } 
} 

public class AccessCode 
{ 
    public int Id { get; set; } 
    public string Code { get; set; } 
} 

public class MyContext : DbContext 
{ 
    public DbSet<Person> Persons { get; set; } 
    public DbSet<AccessCode> AccessCodes { get; set; } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     Database.SetInitializer<MyContext>(new DropCreateDatabaseAlways<MyContext>()); 

     var context = new MyContext(); 

     var person = new Person 
     { 
      FirstName = "Nadege", 
      LastName = "Deroussen", 
      BirthDate = DateTime.Now, 
      AccessCode = new AccessCode { Code = "ABC" } 
     }; 
     context.Persons.Add(person); 

     var accessCode = new AccessCode { Code = "MGH" }; 
     context.AccessCodes.Add(accessCode); 
     context.SaveChanges(); 


     var person2 = context.Persons.FirstOrDefault(); 
     person2.AccessCodeId = 2; 
     // or person2.AccessCode = accessCode; 

     context.SaveChanges(); 

     Console.Write("Person saved !"); 
     Console.ReadLine(); 
    } 
} 

Изменения будут видны в контексте базы данных.

+0

Прежде всего, спасибо вам за то, что нашли время, чтобы ответить/проверить это. @lucask [ForeignKey («AccessCodeId»)] добавлен, потому что в противном случае EF генерировал таблицу с столбцом идентификатора свойства навигации как AccessCode_Id, и я хотел его без «подчеркивания». –

+0

Подойдя к решению @lucask, я попробовал код, который вы опубликовали, но он не работает должным образом.Ожидаемое поведение заключается в том, что свойство AccessCode в человеке должно быть обновлено до этого с Id 2 сразу после того, как я сделаю назначение AccessCodeId. Прямо сейчас это происходит только после вызова метода SaveChanges(). Я не уверен, насколько это возможно. –

+0

Также вы могли бы объяснить строку: Database.SetInitializer (новая DropCreateDatabaseAlways ()); –

4

Вы должны вызвать DetectChanges ChangeTracker в() метод после того, как вы измените значение ключа зарубежной недвижимости

person.AccessCodeId = 2; 
context.ChangeTracker.DetectChanges(); 

Примечание: Я проверил это поведение на @lucask код и код тоже. Ваш код нужен только для исправления второго объявления переменной person.

+0

Благодарим вас за предложение. Это действительно работает. Есть ли способ, которым я могу автоматически запускать этот метод при назначении Id? –

+1

Он будет работать автоматически, если вы объявите все свойства класса Person как 'virtual' и замените' var person = new Person() 'на' var person = context.Persons.Create(); 'Это создаст так называемые _Изменить отслеживание прокси_ вместо простого класса POCO. Некоторая полезная информация здесь [Типы сущностей, поддерживаемые платформой Entity Framework] (http://blog.oneunicorn.com/2011/12/05/entity-types-supported-by-the-entity-framework) и здесь [Если вы использовать прокси-серверы отслеживания изменений Entity Framework?] (http://blog.oneunicorn.com/2011/12/05/should-you-use-entity-framework-change-tracking-proxies) –