Оператор слияния конфликтовал с внешним ключом при вставке таблиц самосоединения - PullRequest
0 голосов
/ 08 июля 2020

У меня два объекта:

public class Header 
{
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        [Key]
        public int Id {get;set;} 
        public string RefNo { get; set; }           
        public decimal TotalAmount { get; set; }
        public ICollection<Detail> Detail { get; set; }
}

public class Detail 
{        
         [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
         [Key]
         public int Id {get;set;} 
         public int HeaderId { get; set; }
         public decimal Amount { get; set; } 
         public int? ParentDetailId { get; set; }     
         public virtual Detail ParentDetail { get; set; }
         public virtual ICollection<Detail> ChlidDetail { get; set; }            
}

Если есть один заголовок и несколько деталей без дочерних деталей, он работает нормально, но при попытке вставить ChildDetail я получаю сообщение об ошибке.

Вот как я пытаюсь вставить:

 Header hdr = new Header();
 hdr.RefNo = "Test";
 hdr.TotalAmount  = Convert.ToDecimal(5.3);
 hdr.Detail = new List<Detail>();
 hdr.Detail.Add(new Detail
                    {
                        HeaderId = hdr.Id,
                        Amount = 50,             
                        ParentDetail = null,            
                        ChlidDetail = new List<Detail>()
                    });

foreach(var dtl in hdr.Detail)
{
    dtl.ChlidDetail.Add(new Detail { HeaderId = hdr.Id, Amount = 25, ParentDetailId = dtl.Id });
}

После добавления всех сущностей, называемых context.SaveChanges(), я получаю сообщение об ошибке:

Конфликт оператора MERGE с ограничением FOREIGN KEY "FK_Detail_Header_HeaderId". Конфликт произошел в базе данных «XXXX», таблица «dbo.Header», столбец «Id»

Вот как там контекстный код (с использованием шаблона репозитория)

вот фрагмент кода контекстного слоя

internal readonly ApiContext context;
internal DbSet<T> entities;
string errorMessage = string.Empty;

public Repository(ApiContext context)
    {
        this.context = context;
        entities = context.Set<T>();
    }

    
 public T Insert(T entity)
   {
      if (entity == null)
         {
            throw new ArgumentNullException("entity");
         }
     entities.Add(entity);
     context.SaveChanges();
     return entity;          
   }

    

Ответы [ 2 ]

1 голос
/ 08 июля 2020

Поскольку все ваши Id столбцы автоматически генерируются базой данных - почему вы устанавливаете их явно в своем коде? Плюс: вы устанавливаете для них значения, которые еще даже не известны (поскольку они будут назначены только тогда, когда вы фактически сохраните свои данные).

Просто не устанавливайте эти столбцы Id и позвольте базе данных обрабатывать присвоение значений и «соединение» родительских и дочерних объектов:

Header hdr = new Header();
hdr.RefNo = "Test";
hdr.TotalAmount  = Convert.ToDecimal(5.3);
hdr.Detail = new List<Detail>();

hdr.Detail.Add(new Detail
                    {
                        // don't use this!  HeaderId = hdr.Id,
                        Amount = 50,             
                        // don't use this!  ParentDetail = null,            
                        ChlidDetail = new List<Detail>()
                    });

foreach(var dtl in hdr.Detail)
{
    dtl.ChlidDetail.Add(new Detail 
                            {
                                 // don't use this! HeaderId = hdr.Id, 
                                 Amount = 25
                                 // don't use this either ParentDetailId = dtl.Id 
                            });
}

И, кстати, это должно быть ChildDetail - не «ChlidDetail» ......

0 голосов
/ 09 июля 2020

Я внес некоторые изменения, и это сработало!

public class Detail 
{        
         [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
         [Key]
         public int Id {get;set;} 
         public int HeaderId { get; set; }
         public Header Header { get; set; }//change
         public decimal Amount { get; set; } 
         public int? ParentDetailId { get; set; }     
         public virtual Detail ParentDetail { get; set; }
         public virtual ICollection<Detail> ChlidDetail { get; set; }            
}

hdr.Detail.Add(new Detail
                    {
                        Header = dtohdr,//change
                        Amount = 50, 
                        ChlidDetail = new List<Detail>()
                    });

foreach(var dtl in hdr.Detail)
{
    dtl.ChlidDetail.Add(new Detail 
                            {
                                 Header = dtohdr,//change
                                 Amount = 25                               
                            });
}

назначил объект Header для подробной таблицы, и это сработало!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...