GraphDiff icon indicating copy to clipboard operation
GraphDiff copied to clipboard

AssociatedCollection write null into the added entity's column

Open bnayae opened this issue 10 years ago • 2 comments

AssociatedCollection write null into the added entity's column

check the following Code First, MS Tests

public class ManyToManyLeft
{
    public ManyToManyLeft()
    {
        Items = new List<ManyToManyRight>();
    }
    public int Id { get; set; }
    public string Title { get; set; }
    public List<ManyToManyRight> Items { get; set; }
}
public class ManyToManyRight
{
    public ManyToManyRight()
    {
        Lefts = new List<ManyToManyLeft>();
    }
    public int Id { get; set; }
    public string Name { get; set; }
    public List<ManyToManyLeft> Lefts { get; set; }
    public List<Others> Others { get; set; }
}
public class Others
{
    public int Id { get; set; }
    public string Name { get; set; }
    public ManyToManyRight Right { get; set; }
}

public class ManyToManyContext: DbContext
{
    public ManyToManyContext()
        : base("ManyToManySample")
    {
        base.Configuration.LazyLoadingEnabled = false;
        base.Configuration.ProxyCreationEnabled = false;
    }

    public DbSet<ManyToManyLeft> LeftSet { get; set; }
    public DbSet<ManyToManyRight> RightSet { get; set; }
}

[TestClass]
public class ManyToMany_Tests
{
    private const bool ENABLE_LOGGING = true;

    #region Setup

    [TestInitialize]
    public void Setup()
    {
        using (var context = new ManyToManyContext())// used to load the related EFConfig before starting transactional operations
        {
            context.Database.ExecuteSqlCommand("DELETE FROM ManyToManyLefts");
            context.Database.ExecuteSqlCommand("DELETE FROM ManyToManyRights");
            context.Database.ExecuteSqlCommand("DELETE FROM Others");
        }
    }

    #endregion // Setup

    #region ToArrayAsync_Test

    [TestMethod]
    public async Task ToArrayAsync_Test()
    {
        var l = new ManyToManyLeft { Title = "L1" };
        var r1 = new ManyToManyRight { Name = "R1" };
        l.Items.Add(r1);
        using (var context = new ManyToManyContext())
        {
            context.LeftSet.Add(l);
            await context.SaveChangesAsync();
        }

        using (var context = new ManyToManyContext())
        {
            var tmpLeft = await context.LeftSet.Include(m => m.Items)
                .AsNoTracking()
                .SingleAsync();
            Assert.AreEqual(1, tmpLeft.Items.Count);
        }

        var r2 = new ManyToManyRight { Name = "R2" };
        l.Items.Add(r2);
        using (var context = new ManyToManyContext())
        {
            SetLogging(context);

            context.UpdateGraph(l,
                map => map.AssociatedCollection( with => with.Items));

            int affected = await context.SaveChangesAsync();
            Assert.AreEqual(2, affected, "right + add relation"); 
        }

        using (var context = new ManyToManyContext())
        {
            var tmpLeft = await context.LeftSet.Include(m => m.Items)
                .AsNoTracking()
                .SingleAsync();
            Assert.AreEqual(2, tmpLeft.Items.Count);
            var tmpRight = await context.RightSet
                .AsNoTracking()
                .SingleAsync(m => m.Name == r2.Name);
        }

        var r3 = new ManyToManyRight { Name = "R3" };
        l.Items.Remove(r2);
        l.Items.Add(r3);

        using (var context = new ManyToManyContext())
        {
            SetLogging(context);
            context.UpdateGraph(l,
                map => map.AssociatedCollection( with => with.Items));

            int affected = await context.SaveChangesAsync();
            Assert.AreEqual(3, affected, "right + add relation + remove relation"); 
        }

        using (var context = new ManyToManyContext())
        {
            var tmpLeft = await context.LeftSet.Include(m => m.Items)
                .AsNoTracking()
                .SingleAsync();
            Assert.AreEqual(2, tmpLeft.Items.Count);
            var tmpRight = await context.RightSet
                .AsNoTracking()
                .SingleAsync(m => m.Name == r2.Name);
        }
    }

    #endregion // ToArrayAsync_Test

    #region SetLogging

    internal static void SetLogging(DbContext context)
    {
        context.Database.Log = sql =>
        {
            if (ENABLE_LOGGING)
                Trace.WriteLine(sql);
        };
    }

    #endregion // SetLogging
}

bnayae avatar Dec 06 '14 06:12 bnayae

if I refactor the following part of the code and supply the added entity to the UpdateGraph it's working, but it's missing the point of graph traversal

        var r2 = new ManyToManyRight { Name = "R2" };
        l.Items.Add(r2);
        r2.Lefts.Add(l);
        using (var context = new ManyToManyContext())
        {
            SetLogging(context);

            //context.UpdateGraph(l,
            //    map => map.AssociatedCollection(with => with.Items));
            context.UpdateGraph(r2,
                map => map.AssociatedCollection(with => with.Lefts));

            int affected = await context.SaveChangesAsync();
            Assert.AreEqual(2, affected, "right + add relation"); 
        }

bnayae avatar Dec 06 '14 07:12 bnayae

Is this maybe the same as #136 ? For me it seems that the GraphDiff method AttachRequiredNavigationProperties does wrong when dealing with associated collections; it overwrites navigation properties on the associated list objects with the input values even if they are null?

mortb avatar Oct 09 '15 13:10 mortb