我有一个简单的雪花模式,从中生成了我的 Entity Framework 模型。
问题是我试图将子实体映射到现有的父级和/或祖 parent 实体,但仍将其插入。

我遵循了这一点:



有趣的是,即使父实体的EntityState是“未更改”的, Entity Framework 仍会尝试将其插入。

模式



CarRepository.Save()方法

public void Save(Car car)
    {
        using (DBContext context = new DBContext())
        {
            // No need to save if it already exists
            if ( context.Cars.FirstOrDefault(x => x.RegistrationNumber == car.RegistrationNumber) != null)
            {
                return;
            }
            else
            {
                // Check if the parent POCOs exist in the DB.
                Model existingModel = context.Models.FirstOrDefault(x => x.Name == car.Model.Name);
                Manufacturer existingManufacturer = context.Manufacturers.FirstOrDefault(x=> x.Name == car.Model.Manufacturer.Name)
                Trader existingTrader = context.Traders.FirstOrDefault(x=> x.Name == car.Trader.Name)
                TraderCompany existingTraderCompany = context.TraderCompanys.FirstOrDefault(x=> x.Name == car.Trader.TraderCompany.Name)

                context.ContextOptions.LazyLoadingEnabled = false;

                //Attach to the context if existing in the DB, i.e mark the existing POCOs not to be added the DB
                if (existingModel != null)
                {
                    car.Model = existingModel;
                    Assert.IsTrue(context.ObjectStateManager.GetObjectStateEntry(car.Model).State == EntityState.Unchanged);
                }

                if (existingManufacturer != null)
                {
                    car.Model.Manufacturer = existingManufacturer;
                    Assert.IsTrue(context.ObjectStateManager.GetObjectStateEntry(car.Model.Manufacturer).State == EntityState.Unchanged);
                }

                if (existingTrader != null)
                {
                    car.Trader = existingTrader;
                    Assert.IsTrue(context.ObjectStateManager.GetObjectStateEntry(car.Trader).State == EntityState.Unchanged);
                }

                if (existingTraderCompany != null)
                {
                    car.Trader.TraderCompany = existingTraderCompany;
                    Assert.IsTrue(context.ObjectStateManager.GetObjectStateEntry(car.Trader.TraderCompany).State == EntityState.Unchanged);
                }

                //Mark the Car for Addition to the DB
                context.Cars.AddObject(car);
                context.ObjectStateManager.ChangeObjectState(car, EntityState.Added);


                //If the POCOs do not exist in the DB mark them for addition
                if (existingModel == null)
                {
                   context.ObjectStateManager.ChangeObjectState(car.Model,EntityState.Added);
                }

                if (existingManufacturer == null)
                {
                    context.ObjectStateManager.ChangeObjectState(car.Model.Manufacturer,EntityState.Added);
                }

                if (existingTrader == null)
                {
                    context.ObjectStateManager.ChangeObjectState(car.Trader,EntityState.Added);
                }

                if (existingTraderCompany == null)
                {
                    context.ObjectStateManager.ChangeObjectState(car.Trader.TraderCompany,EntityState.Added);
                }

                context.SaveChanges();

            }
        }
    }

编辑:

经过几天的修补,我设法提出了一个对我有用的解决方法

似乎正在传递到CarRepository.Save()的Car具有某种内部上下文,这是无法检测到的……如此,无法将其与该上下文/分离,并且将其添加到CarRepository.Save()中。为了将其实际添加到此上下文中,我深度/惰性复制了Car对象及其导航属性(如果存在)。

解决方法

public void Save(Car car)
{
    using (DBContext context = new DBContext())
    {
        // No need to save if it already exists
        if ( context.Cars
                    .Any(x => x.RegistrationNumber == car.RegistrationNumber))
        {
            return;
        }
        else
        {
            //Assign scalar properties to the deep copy
            Car carToBeSaved = new Car
            {
                carToBeSaved.RegistrationNumber = car.RegistrationNumber,
                carToBeSaved.Price = car.Price
            }


            //Car -> Trader -> ...
            if(car.Trader != null)
            {
                Trader existingTrader =
                    context.Traders
                           .FirstOrDefault(x => x.Name == car.Trader.Name);

                //If exists in DB assign, if not deep copy
                carToBeSaved.Trader = existingTrader ??
                    new Trader
                    {
                        Name = car.Trader.Name,
                        JobTitle = car.Trader.JobTitle
                    }

                //Car -> Trader -> TraderCompany
                if(car.Trader.TraderCompany != null)
                {
                    TraderCompany existingTraderCompany =
                        context.TradersCompanys
                               .FirstOrDefault(x => x.Name == car.Trader
                                                                 .TraderCompany
                                                                 .Name);

                    //If exists in DB assign, if not deep copy
                    carToBeSaved.Trader.TraderCompany = existingTraderCompany ??
                        new TraderCompany
                        {
                            Name = car.Trader.TraderCompany.Name,
                            Address = car.Trader.TraderCompany.Address,
                            PhoneNumber = car.Trader.TraderCompany.PhoneNumber
                        }
                }
            }

            //Car -> Model -> ...
            if(car.Model != null)
            {
                Model existingModel =
                    context.Models
                           .FirstOrDefault(x => x.Name == car.Model.Name);

                //If exists in DB assign, if not deep copy
                carToBeSaved.Model = existingModel ??
                    new Model
                    {
                        Name = car.Model.Name
                    }

                //Car -> Model -> Manufacturer
                if(car.Model.Manufacturer != null)
                {
                    Manufacturer existingManufacturer =
                        context.Manufacturers
                               .FirstOrDefault(x => x.Name == car.Model
                                                                 .Manufacturer
                                                                 .Name);

                    //If exists in DB assign, if not deep copy
                    carToBeSaved.Model.Manufacturer = existingManufacturer ??
                    new Manufacturer
                        {
                            Name = car.Model.Manufacturer.Name
                        }
                }
            }

            //Mark the Car for Addition to the DB
            context.Cars.AddObject(car);
            context.SaveChanges();

        }
    }
}

如果有人对此有任何想法,请分享。

谢谢。

最佳答案

关于此类问题,我找到的最可靠的方法是使用现有对象的ID,而不是关联实体实例。因此,您可以在找到现有交易者之后,像这样设置交易者的“外来” key :

car.TraderId = existingTrader.Id;

在一段时间内,这对我来说似乎是一种黑客,但是在2013年4月的MSDN杂志上,我读到Julie Lerman也推荐这种方法。

10-06 00:37