Каков правильный порядок сохранения графа обособленных объектов в Entity Framework 6? - PullRequest
0 голосов
/ 11 октября 2018

Я работаю над сохранением сложных отдельных объектов в рамках сущности.Я извлекаю объекты из веб-API и десериализую json в объекты c #.Упрощенная версия части моих сущностей выглядит следующим образом:

class Order{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    long Id {get; set; }

    [ForeignKey("Billing")]
    long BillingId { get; set; }

    Address Billing { get; set; }

    [ForeignKey("Shipping")]
    long ShippingId { get; set; }

    Address Shipping{ get; set; }
}

class Address{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    long Id { get; set;}

    [ForeignKey("Country")]
    long CountryId { get; set; }

    Country Country { get; set; }
}

class Country{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    long Id { get; set;} 
}

Я просматриваю граф объектов и пытаюсь определить, какие объекты мне нужно вставить, а какие просто нужно обновить.С кодом, подобным следующему (реальный код работает с универсальной функцией, я просто написал все это, чтобы лучше ее использовать):

Order order = restClient.Get<Order>(1);
using(var context = new MyContext()){
    if (order.Billing != null){
        if(order.Billing.Country != null){
                var dbBillingCountry = context.Set<Country>().Find(order.Billing.Country.Id);
                if(dbBillingCountry == null){
                    context.Set<Country>().Add(order.Billing.Country);
                }
                else{
                    context.Entry(dbBillingCountry).CurrentValues.SetValues(order.Billing.Country);
                    //order.Billing.Country = dbBillingCountry;
                    context.Entry(dbBillingCountry).State = EntityState.Modified;
                }
        }

        var dbBilling = context.Set<Address>().Find(order.Billing.Id);
        if(dbBilling == null){
            context.Set<Address>().Add(order.Billing);
        }
        else{
            context.Entry(dbBilling).CurrentValues.SetValues(order.Billing);
            //order.Billing = dbBilling;
            context.Entry(dbBilling).State = EntityState.Modified;
        }
        //db.SaveChanges();
    }
    if (order.Shipping != null){
        if(order.Shipping.Country != null){
                var dbShippingCountry = context.Set<Country>().Find(order.Shipping.Country.Id);
                if(dbShippingCountry == null){
                    context.Set<Country>().Add(order.Shipping.Country);
                }
                else{
                    context.Entry(dbShippingCountry).CurrentValues.SetValues(order.Shipping.Country);
                    //order.Shipping.Country = dbShippingCountry;
                    context.Entry(dbShippingCountry).State = EntityState.Modified;
                }
        }
        var dbShipping = context.Set<Address>().Find(order.Shipping.Id);
        if(dbShipping == null){
            context.Set<Address>().Add(order.Shipping);
        }
        else{
            context.Entry(dbShipping).CurrentValues.SetValues(order.Shipping);
            //order.Shipping = dbShipping;
            context.Entry(dbShipping).State = EntityState.Modified;
        }
        //db.SaveChanges();
    }
    var dbOrder = context.Set<Order>().Find(order.Id);
    if(dbOrder == null){
        context.Set<Order>().Add(order);
    }
    else{
        context.Entry(dbOrder).CurrentValues.SetValues(order);
        //order = dbOrder;
        context.Entry(dbOrder).State = EntityState.Modified;
    }
context.SaveChanges();
}

В случае, когда order.Billing - это тот же объект /значения как order.Shipping в context.SaveChanges() я получаю ошибку, потому что EF пытается вставить адрес, а перед этим страну дважды с тем же ключом.Я попытался установить ссылку на базу данных / локальную сущность, которая возвращает contex.Find, но это не исправляет.Как я могу сказать контексту, что это одни и те же объекты?

...