3

I have a model as below

public class Lesson
{

    public int Id { get; set; }
    public Section Div { get; set; }

}

public class Section
{

    public int Id { get; set; }

    public string Name { get; set; }
}

I also have DB Context as below

public class MyContext : DbContext
{

    public MyContext() : base("DefaultConnection")
    {
        this.Configuration.LazyLoadingEnabled = false;
        this.Configuration.ProxyCreationEnabled = false;
    }

    public DbSet<Lesson> Lessons { get; set; }
    public DbSet<Section> Sections { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
    }

}

Then I use the following code to call the database

            using (MyContext c = new EFTest.MyContext())
            {

                Lesson d = new EFTest.Lesson();
                Section ed = new EFTest.Section() { Name = "a" };
                d.Div = ed;

                c.Entry(d.Div).State = EntityState.Detached;

                c.Lessons.Add(d);
                c.SaveChanges();
            }

I am expecting this code to save just the Lesson object, not to save the full graph of Lesson and Section, but what happens is that it saves the full graph. How do I prevent it from doing that?

Sisyphus
  • 900
  • 12
  • 32
  • with .AsNoTracking() relationship fixup should not take place and your DbSets should have no other references. Maybe you have to disable ChangeTracking as well, depending on what you do between retrieval and saving the data back. – DevilSuichiro Sep 25 '17 at 09:51
  • I am not retrieving data, as you can see in the sample I am creating object from scratch then sending them to the database. – Sisyphus Sep 25 '17 at 09:54
  • oh, I just noticed that. What happens when you swap the statements .Add and .State=Detached? DbSet.Add() should set the states of the object tree to added, overriding your previous statement that added an entry of this object, setting its state to detached. – DevilSuichiro Sep 25 '17 at 09:57
  • That did the trick, thank you. However I have another problem now, after I have added the Lesson I would like to add the Section, so I call c.Sections.Add(d); , but I find that the Section FK column in the Lessons table stay null, even though a relation exists between Lesson and Section as in the code above. I am expecting EF to add the Section, grab its id and insert it into the Section FK column of the relevant record in the Lessons table. – Sisyphus Sep 25 '17 at 10:14
  • it will do that when both objects are in the context (added state), the mapped navigation properties between them are filled and .SaveChanges is called. if you want to add the object sequentially, you'll have to grab the id value yourself and set the FK (the id property will be set after the .SaveChanges() call) – DevilSuichiro Sep 25 '17 at 10:23
  • Could you clarify what actually do you want? First you are saying you want to add *only* the `Lesson`, then you say you want to add them both. The two scenarios are different and require different code sequence. So what it should be? – Ivan Stoev Sep 25 '17 at 10:33
  • I want to manually call an Add method per object, so if object graph has 5 objects I call 5 Add methods one per object, and each Add method is located at the appropriate repository. – Sisyphus Sep 25 '17 at 10:35
  • @DevilSuichiro would you kindly explain briefly with pseudo code? – Sisyphus Sep 25 '17 at 13:05

1 Answers1

0

When you add an entity to DbSet, entityframework will add all of its relative. You need to detach the entity you don't want to add, after adding parent entity to DbSet.

using (MyContext c = new EFTest.MyContext())
{

    Lesson d = new EFTest.Lesson();
    Section ed = new EFTest.Section() { Name = "a" };
    d.Div = ed;

    c.Lessons.Add(d);

    c.Entry(d.Div).State = EntityState.Detached;

    c.SaveChanges();
}

if you want to add section, related to the lesson , you need to use the same context, or create a new context and load the lesson.

you can use this code

using (MyContext c = new EFTest.MyContext())
{

    Lesson d = new EFTest.Lesson();
    Section ed = new EFTest.Section() { Name = "a" };
    d.Div = ed;

    c.Lessons.Add(d);

    c.Entry(d.Div).State = EntityState.Detached;

    c.SaveChanges();

    //you can use this code
        ed.Lesson = d;
    // or this code
        d.Div = ed;

    c.Sections.Add(ed);
    c.SaveChanges();
}
Kahbazi
  • 14,331
  • 3
  • 45
  • 76
  • Thank you for your answer, now I am having another problem, could you please check the comments on the initial post may be you could help me. – Sisyphus Sep 25 '17 at 10:17
  • But I don't have a property in the Section that points to Lesson. – Sisyphus Sep 25 '17 at 10:27
  • @Sisyphus you need to add it, either add a Lesson, or a List based on your needs. It shouldn't change your database, or require a migration. because the relation already exists. – Kahbazi Sep 25 '17 at 10:29
  • I am also not sure if relationship fixup will work on detached entries. The inverse navigation property should not be required for relationship fixup though. – DevilSuichiro Sep 25 '17 at 10:30
  • @Arvin yes I think it will work, but this pollutes my domain model with an extra unnecessary relation, is there other solution? – Sisyphus Sep 25 '17 at 13:04
  • @Sisyphus you can also add your section to your lesson again, I'll edit my asnwer – Kahbazi Sep 25 '17 at 14:47