Update Navigation Property with Entity.CurrentValues.SetValues
Asked Answered
K

2

3

I have a Kalem Entity with a collection of DigerKalemMaliyetleri property, which is a collection of MaliyetBirimi objects. DigerKalemMaliyetleri is of JSON type and stored at the same table as a JSON column.

public class Kalem
{
    public int Id { get; set; }
    [Column(TypeName = "json")]
    public ICollection<MaliyetBirimi> DigerKalemMaliyetleri { get; set; }
}
public class MaliyetBirimi
{
    public int? DovizCinsi { get; set; }
    public decimal? Maliyet { get; set; }
}

When I try to update entity with only DigerKalemMaliyetleri property changed:

DataContext.Entry<Kalem>(first).CurrentValues.SetValues(second);

SQL Update command isn't executed and database record is not updated.

How could I update the entity without explicitly setting DigerKalemMaliyetleri property?

Regards

Kanya answered 15/2, 2021 at 10:37 Comment(0)
J
5

I had the same problem, you cann't actually use SetValues to update navigation property, you nead instead use DataContext.Update(YourNewObj) and then DataContext.SaveChanges();, or if you want to use SetValues approach, you need:

-Get the exist entry

Kalem existObj = DataContext.Kalems.Find(YourNewObj.Id);

-Loop in navigations of updating entry and the existing one to set the values of updating entry:

foreach(var navObj in DataContext.Entry(YourNewObj).Navigations)
 {
   foreach(var navExist in DatatContext.Entry(existObj).Navigations)
    {
     if(navObj.Metadata.Name == navExist.MetaData.Name)
       navExist.CurrentValue = navObj.CurrentValue;
    }
 }

-Update also changes of direct properties:

DataContext.Entry(existObj).CurrentValues.SetValues(YourNewObj);

-Save your Updating:

DataContext.SaveChanges();

You can also check if you need to load your Navigations before going in foreach loop, otherwise you will get an error. Please if you see beter scenario, correct me.

Jackshaft answered 5/3, 2021 at 11:30 Comment(0)
P
0

It's hard to know exactly what you're doing without a complete code sample. Note also that you're trying to set all properties of first from second, including e.g. the Id, which is probably not what you want.

Here's a complete code sample which works for me:

await using (var ctx = new BlogContext())
{
    await ctx.Database.EnsureDeletedAsync();
    await ctx.Database.EnsureCreatedAsync();

    ctx.Kalem.Add(new()
    {
        DigerKalemMaliyetleri = new List<MaliyetBirimi>()
        {
            new() { DovizCinsi = 1, Maliyet = 2 }
        }
    });

    await ctx.SaveChangesAsync();
}

await using (var ctx = new BlogContext())
{
    var first = ctx.Kalem.Find(1);

    var second = new Kalem
    {
        DigerKalemMaliyetleri = new List<MaliyetBirimi>()
        {
            new() { DovizCinsi = 3, Maliyet = 4 }
        }
    };

    ctx.Entry(first).Property(k => k.DigerKalemMaliyetleri).CurrentValue = second.DigerKalemMaliyetleri;

    await ctx.SaveChangesAsync();
}


public class BlogContext : DbContext
{
    public DbSet<Kalem> Kalem { get; set; }

    static ILoggerFactory ContextLoggerFactory
        => LoggerFactory.Create(b => b.AddConsole().AddFilter("", LogLevel.Information));

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder
            .UseNpgsql(@"Host=localhost;Username=test;Password=test")
            .EnableSensitiveDataLogging()
            .UseLoggerFactory(ContextLoggerFactory);
}

public class Kalem
{
    public int Id { get; set; }
    [Column(TypeName = "json")]
    public ICollection<MaliyetBirimi> DigerKalemMaliyetleri { get; set; }
}

public class MaliyetBirimi
{
    public int? DovizCinsi { get; set; }
    public decimal? Maliyet { get; set; }
}
Prehension answered 26/2, 2021 at 9:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.