代码优先 - 在分配ID时未加载外键引用

时间:2012-05-24 12:54:41

标签: c# entity-framework ef-code-first auto-update

我有以下C#Entity Framework代码定义的第一个实体:

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,所以如果这没有意义,请原谅。

3 个答案:

答案 0 :(得分:4)

更改外键属性值后,必须调用ChangeTracker的DetectChanges()方法

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

注意:我已经在@lucask代码和您的代码上测试了这种行为。您的代码只需要更正person变量的第二个声明。

答案 1 :(得分: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()之前),Child属性也会被正确更新。感谢所有提出宝贵意见的人。

enter image description here

答案 2 :(得分:1)

好吧,我不同意@David。 Code First,Database First或Model First只是实现相同目标的不同方法。 Code First和Data Annotations或Fluent API非常强大。你只需要学习如何使用它。

您的代码将有效。首先删除[ForeignKey("AccessCodeId")]。它是多余的,无论如何你把它放在错误的属性上。 Code First会通过约定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();
    }
}

更改将在数据库上下文中显示。