it-swarm.com.ru

Невозможно изменить отношение, так как одно или несколько свойств внешнего ключа не могут быть равны нулю

Я получаю эту ошибку, когда я получаю GetById () для сущности, а затем устанавливаю коллекцию дочерних сущностей в свой новый список, который поступает из представления MVC.

Операция не выполнена: отношения не могут быть изменены потому что один или несколько внешних ключей свойства не обнуляются. Когда изменение сделано в отношениях, Связанное свойство внешнего ключа установлено в нулевое значение. Если внешний ключ делает не поддерживает нулевые значения, новый отношения должны быть определены, свойство внешнего ключа должно быть назначено другое ненулевое значение или несвязанный объект должен быть удален.

Я не совсем понимаю эту строку:

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

Зачем мне менять отношения между двумя сущностями? Он должен оставаться неизменным на протяжении всего срока службы всего приложения.

Код, в котором возникает исключение, - это простое назначение измененных дочерних классов в коллекции существующему родительскому классу. Мы надеемся, что это поможет удалить дочерние классы, добавить новые и модификации. Я бы подумал, что Entity Framework справится с этим.

Строки кода можно перевести на:

var thisParent = _repo.GetById(1);
thisParent.ChildItems = modifiedParent.ChildItems();
_repo.Save();
163
jaffa

Вы должны удалить старые дочерние элементы thisParent.ChildItems один за другим вручную. Entity Framework не делает это для вас. Наконец, он не может решить, что вы хотите сделать со старыми дочерними элементами - хотите ли вы выбросить их или хотите сохранить и назначить их другим родительским объектам. Вы должны сообщить Entity Framework о своем решении. Но одно из этих двух решений вы ДОЛЖНЫ принять, поскольку дочерние объекты не могут жить в одиночестве без ссылки на какой-либо родительский элемент в базе данных (из-за ограничения внешнего ключа). Это в основном то, что говорит исключение. 

Правка

Что бы я сделал, если бы дочерние элементы могли быть добавлены, обновлены и удалены:

public void UpdateEntity(ParentItem parent)
{
    // Load original parent including the child item collection
    var originalParent = _dbContext.ParentItems
        .Where(p => p.ID == parent.ID)
        .Include(p => p.ChildItems)
        .SingleOrDefault();
    // We assume that the parent is still in the DB and don't check for null

    // Update scalar properties of parent,
    // can be omitted if we don't expect changes of the scalar properties
    var parentEntry = _dbContext.Entry(originalParent);
    parentEntry.CurrentValues.SetValues(parent);

    foreach (var childItem in parent.ChildItems)
    {
        var originalChildItem = originalParent.ChildItems
            .Where(c => c.ID == childItem.ID && c.ID != 0)
            .SingleOrDefault();
        // Is original child item with same ID in DB?
        if (originalChildItem != null)
        {
            // Yes -> Update scalar properties of child item
            var childEntry = _dbContext.Entry(originalChildItem);
            childEntry.CurrentValues.SetValues(childItem);
        }
        else
        {
            // No -> It's a new child item -> Insert
            childItem.ID = 0;
            originalParent.ChildItems.Add(childItem);
        }
    }

    // Don't consider the child items we have just added above.
    // (We need to make a copy of the list by using .ToList() because
    // _dbContext.ChildItems.Remove in this loop does not only delete
    // from the context but also from the child collection. Without making
    // the copy we would modify the collection we are just interating
    // through - which is forbidden and would lead to an exception.)
    foreach (var originalChildItem in
                 originalParent.ChildItems.Where(c => c.ID != 0).ToList())
    {
        // Are there child items in the DB which are NOT in the
        // new child item collection anymore?
        if (!parent.ChildItems.Any(c => c.ID == originalChildItem.ID))
            // Yes -> It's a deleted child item -> Delete
            _dbContext.ChildItems.Remove(originalChildItem);
    }

    _dbContext.SaveChanges();
}

Примечание: это не проверено. Предполагается, что коллекция дочерних элементов имеет тип ICollection. (У меня обычно есть IList, а затем код выглядит немного по-другому.) Я также убрал все абстракции репозитория, чтобы упростить его.

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

145
Slauma

Причина, по которой вы сталкиваетесь с этим, заключается в разнице между составом и агрегацией

В композиции дочерний объект создается при создании родителя и уничтожается при уничтожении его родителя . Таким образом, его время жизни контролируется его родителем. например Сообщение в блоге и его комментарии. Если сообщение удалено, его комментарии должны быть удалены. Нет смысла оставлять комментарии к несуществующему сообщению. То же самое для заказов и элементов заказа.

В агрегации дочерний объект может существовать независимо от его родителя . Если родитель уничтожен, дочерний объект все еще может существовать, так как он может быть добавлен к другому родителю позже. например: связь между списком воспроизведения и песнями в этом списке воспроизведения. Если список воспроизведения удален, песни не должны быть удалены. Они могут быть добавлены в другой список воспроизведения.

Entity Framework различает агрегацию и составные отношения следующим образом:

  • Для композиции: ожидается, что дочерний объект будет иметь составной первичный ключ (ParentID, ChildID). Это сделано специально, так как идентификаторы детей должны быть в пределах их родителей. 

  • Для агрегации: он ожидает, что свойство внешнего ключа в дочернем объекте будет обнуляемым.

Итак, причина, по которой вы столкнулись с этой проблемой, заключается в том, как вы установили свой первичный ключ в своей дочерней таблице. Он должен быть составным, но это не так. Итак, Entity Framework рассматривает эту ассоциацию как агрегацию, что означает, что когда вы удаляете или очищаете дочерние объекты, она не собирается удалять дочерние записи. Он просто удалит связь и установит для соответствующего столбца внешнего ключа значение NULL (чтобы эти дочерние записи впоследствии могли быть связаны с другим родителем). Поскольку ваш столбец не допускает NULL, вы получите исключение, которое вы упомянули. 

Решения:

1. Если у вас есть веская причина не использовать составной ключ, вам необходимо явно удалить дочерние объекты. И это может быть сделано проще, чем решения, предложенные ранее:

context.Children.RemoveRange(parent.Children);

2- В противном случае, установив правильный первичный ключ на вашей дочерней таблице, ваш код будет выглядеть более значимым:

parent.Children.Clear();
81
Mosh

Это очень большая проблема. Что на самом деле происходит в вашем коде:

  • Вы загружаете Parent из базы данных и получаете прикрепленный объект
  • Вы заменяете его дочернюю коллекцию новой коллекцией отдельных детей
  • Вы сохраняете изменения, но во время этой операции все дочерние элементы рассматриваются как добавленные, поскольку EF не знала о них до этого времени. Таким образом, EF пытается установить нулевой внешний ключ старых дочерних элементов и вставить все новые дочерние = = повторяющиеся строки.

Теперь решение действительно зависит от того, что вы хотите сделать и как бы вы хотели это сделать? 

Если вы используете ASP.NET MVC, вы можете попробовать использовать UpdateModel или TryUpdateModel .

Если вы хотите просто обновить существующих потомков вручную, вы можете просто сделать что-то вроде:

foreach (var child in modifiedParent.ChildItems)
{
    context.Childs.Attach(child); 
    context.Entry(child).State = EntityState.Modified;
}

context.SaveChanges();

Присоединение на самом деле не нужно (установка состояния на Modified также присоединит сущность), но мне это нравится, потому что это делает процесс более очевидным.

Если вы хотите изменить существующий, удалить существующий и вставить новые дочерние элементы, вы должны сделать что-то вроде:

var parent = context.Parents.GetById(1); // Make sure that childs are loaded as well
foreach(var child in modifiedParent.ChildItems)
{
    var attachedChild = FindChild(parent, child.Id);
    if (attachedChild != null)
    {
        // Existing child - apply new values
        context.Entry(attachedChild).CurrentValues.SetValues(child);
    }
    else
    {
        // New child
        // Don't insert original object. It will attach whole detached graph
        parent.ChildItems.Add(child.Clone());
    }
}

// Now you must delete all entities present in parent.ChildItems but missing
// in modifiedParent.ChildItems
// ToList should make copy of the collection because we can't modify collection
// iterated by foreach
foreach(var child in parent.ChildItems.ToList())
{
    var detachedChild = FindChild(modifiedParent, child.Id);
    if (detachedChild == null)
    {
        parent.ChildItems.Remove(child);
        context.Childs.Remove(child); 
    }
}

context.SaveChanges();
67
Ladislav Mrnka

Я нашел этот ответ гораздо более полезным для той же ошибки . Кажется, что EF не нравится, когда вы удаляете, он предпочитает удалить.

Вы можете удалить коллекцию записей, прикрепленных к такой записи.

order.OrderDetails.ToList().ForEach(s => db.Entry(s).State = EntityState.Deleted);

В этом примере для всех подробных записей, прикрепленных к ордеру, установлено состояние «Удалить». (При подготовке к добавлению обратно обновленных сведений в рамках обновления заказа)

35
Greg Little

Я понятия не имею, почему два других ответа так популярны! 

Я полагаю, что вы были правы, предполагая, что среда ORM должна справиться с этим - в конце концов, это то, что она обещает предоставить. В противном случае модель вашего домена будет повреждена постоянными проблемами. NHibernate справится с этим, если вы правильно настроите параметры каскада. В Entity Framework это также возможно, они просто ожидают, что вы будете следовать лучшим стандартам при настройке модели базы данных, особенно когда им нужно определить, какое каскадирование следует выполнить:

Вы должны определить отношения родитель - потомок правильно, используя " идентификационные отношения ".

Если вы сделаете это, Entity Framework узнает, что дочерний объект является идентифицированным родительским объектом, и, следовательно, это должна быть ситуация "cascade-delete-orphans".

Кроме вышеперечисленного, вам может понадобиться может (из опыта NHibernate)

thisParent.ChildItems.Clear();
thisParent.ChildItems.AddRange(modifiedParent.ChildItems);

вместо полной замены списка. 

ОБНОВЛЕНИЕ

Комментарий @ Slauma напомнил мне, что отдельные объекты являются еще одной частью общей проблемы. Чтобы решить эту проблему, вы можете использовать подход связывания пользовательских моделей, который создает ваши модели, пытаясь загрузить его из контекста. Этот пост в блоге показывает пример того, что я имею в виду.

19
Andre Luus

Если вы используете AutoMapper с Entity Framework в том же классе, вы можете столкнуться с этой проблемой. Например, если ваш класс

class A
{
    public ClassB ClassB { get; set; }
    public int ClassBId { get; set; }
}

AutoMapper.Map<A, A>(input, destination);

Это попытается скопировать оба свойства. В этом случае ClassBId не обнуляется. Так как AutoMapper скопирует destination.ClassB = input.ClassB;, это вызовет проблему.

Установите свой AutoMapper на Игнорировать свойство ClassB.

 cfg.CreateMap<A, A>()
     .ForMember(m => m.ClassB, opt => opt.Ignore()); // We use the ClassBId
9
jsgoupil

Это происходит потому, что дочерний объект помечен как измененный, а не как удаленный.

И модификация, которую EF выполняет с дочерним объектом при выполнении parent.Remove(child), просто устанавливает ссылку на его родителя на null.

Вы можете проверить EntityState дочернего элемента, введя следующий код в Immediate Window Visual Studio при возникновении исключения после выполнения SaveChanges():

_context.ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Modified).ElementAt(X).Entity

где X следует заменить удаленным объектом.

Если у вас нет доступа к ObjectContext для выполнения _context.ChildEntity.Remove(child), вы можете решить эту проблему, сделав внешний ключ частью первичного ключа дочерней таблицы.

Parent
 ________________
| PK    IdParent |
|       Name     |
|________________|

Child
 ________________
| PK    IdChild  |
| PK,FK IdParent |
|       Name     |
|________________|

Таким образом, если вы выполните parent.Remove(child), EF правильно пометит сущность как удаленную.

4
Mauricio Ramalho

У меня просто была та же ошибка . У меня есть две таблицы с родительским дочерним отношением, но я настроил «каскад удаления» для столбца внешнего ключа в определении таблицы дочерней таблицы…. Поэтому, когда я вручную удалить родительскую строку (через SQL) в базе данных, она автоматически удалит дочерние строки.

Однако это не сработало в EF, ошибка, описанная в этом потоке, обнаружилась . Причина этого состояла в том, что в моей модели данных сущности (файл edmx) свойства ассоциации между родительской и дочерней таблицей не были правильно . Опция End1 OnDelete была настроена на none («Конец1» в моей модели - это конец, кратность которого равна 1).

Я вручную изменил параметр End1 OnDelete на Cascade и чем это сработало . Я не знаю, почему EF не может подобрать это, когда я обновляю модель из базы данных (у меня есть база данных первой модели).

Для полноты вот так выглядит мой код для удаления:

   public void Delete(int id)
    {
        MyType myObject = _context.MyTypes.Find(id);

        _context.MyTypes.Remove(myObject);
        _context.SaveChanges(); 
   }    

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

3
Martin

Вы должны вручную очистить коллекцию ChildItems и добавить в нее новые элементы: 

thisParent.ChildItems.Clear();
thisParent.ChildItems.AddRange(modifiedParent.ChildItems);

После этого вы можете вызвать метод расширения DeleteOrphans, который будет обрабатывать осиротевшие объекты (он должен вызываться между методами DetectChanges и SaveChanges). 

public static class DbContextExtensions
{
    private static readonly ConcurrentDictionary< EntityType, ReadOnlyDictionary< string, NavigationProperty>> s_navPropMappings = new ConcurrentDictionary< EntityType, ReadOnlyDictionary< string, NavigationProperty>>();

    public static void DeleteOrphans( this DbContext source )
    {
        var context = ((IObjectContextAdapter)source).ObjectContext;
        foreach (var entry in context.ObjectStateManager.GetObjectStateEntries(EntityState.Modified))
        {
            var entityType = entry.EntitySet.ElementType as EntityType;
            if (entityType == null)
                continue;

            var navPropMap = s_navPropMappings.GetOrAdd(entityType, CreateNavigationPropertyMap);
            var props = entry.GetModifiedProperties().ToArray();
            foreach (var prop in props)
            {
                NavigationProperty navProp;
                if (!navPropMap.TryGetValue(prop, out navProp))
                    continue;

                var related = entry.RelationshipManager.GetRelatedEnd(navProp.RelationshipType.FullName, navProp.ToEndMember.Name);
                var enumerator = related.GetEnumerator();
                if (enumerator.MoveNext() && enumerator.Current != null)
                    continue;

                entry.Delete();
                break;
            }
        }
    }

    private static ReadOnlyDictionary<string, NavigationProperty> CreateNavigationPropertyMap( EntityType type )
    {
        var result = type.NavigationProperties
            .Where(v => v.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many)
            .Where(v => v.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One || (v.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne && v.FromEndMember.GetEntityType() == v.ToEndMember.GetEntityType()))
            .Select(v => new { NavigationProperty = v, DependentProperties = v.GetDependentProperties().Take(2).ToArray() })
            .Where(v => v.DependentProperties.Length == 1)
            .ToDictionary(v => v.DependentProperties[0].Name, v => v.NavigationProperty);

        return new ReadOnlyDictionary<string, NavigationProperty>(result);
    }
}
2
Sat

Я столкнулся с этой проблемой сегодня и хотел поделиться своим решением. В моем случае решение заключалось в удалении дочерних элементов перед получением родительского элемента из базы данных.

Ранее я делал это, как в коде ниже. Затем я получу ту же ошибку, указанную в этом вопросе.

var Parent = GetParent(parentId);
var children = Parent.Children;
foreach (var c in children )
{
     Context.Children.Remove(c);
}
Context.SaveChanges();

Что сработало для меня, так это сначала получить дочерние элементы, используя parentId (внешний ключ), а затем удалить эти элементы. Затем я могу получить Parent из базы данных, и в этот момент у него больше не должно быть дочерних элементов, и я могу добавлять новые дочерние элементы.

var children = GetChildren(parentId);
foreach (var c in children )
{
     Context.Children.Remove(c);
}
Context.SaveChanges();

var Parent = GetParent(parentId);
Parent.Children = //assign new entities/items here
2
Dino Bansigan

Я пробовал эти и многие другие решения, но ни одно из них не сработало. Так как это первый ответ на Google, я добавлю свое решение здесь.

Метод, который хорошо работал для меня, заключался в том, чтобы исключать отношения во время коммитов, поэтому EF ничего не испортил. Я сделал это, заново найдя родительский объект в DBContext и удалив его. Поскольку все свойства навигации вновь найденного объекта равны нулю, дочерние отношения игнорируются при фиксации.

var toDelete = db.Parents.Find(parentObject.ID);
db.Parents.Remove(toDelete);
db.SaveChanges();

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

1
Steve

Этот тип решения помог мне:

Parent original = db.Parent.SingleOrDefault<Parent>(t => t.ID == updated.ID);
db.Childs.RemoveRange(original.Childs);
updated.Childs.ToList().ForEach(c => original.Childs.Add(c));
db.Entry<Parent>(original).CurrentValues.SetValues(updated);

Важно сказать, что это удаляет все записи и вставляет их снова . Но для моего случая (меньше 10) это нормально.

Я надеюсь, что это помогает.

1
Wagner Bertolini Junior

Я использовал решение Моша , но мне было неочевидно, как правильно реализовать ключ композиции в коде. 

Итак, вот решение:

public class Holiday
{
    [Key, Column(Order = 0), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int HolidayId { get; set; }
    [Key, Column(Order = 1), ForeignKey("Location")]
    public LocationEnum LocationId { get; set; }

    public virtual Location Location { get; set; }

    public DateTime Date { get; set; }
    public string Name { get; set; }
}
1
PeterB

Я также решил свою проблему с ответом Моша и я подумал ответом PeterB было немного, потому что он использовал перечисление в качестве внешнего ключа. Помните, что вам нужно будет добавить новую миграцию после добавления этого кода.

Я также могу рекомендовать этот блог для других решений:

http://www.kianryan.co.uk/2013/03/orphaned-child/

Код:

public class Child
{
    [Key, Column(Order = 0), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public string Heading { get; set; }
    //Add other properties here.

    [Key, Column(Order = 1)]
    public int ParentId { get; set; }

    public virtual Parent Parent { get; set; }
}
0
Ogglas

Я столкнулся с этой проблемой раньше, чем через несколько часов, и попробовал все, но в моем случае решение отличалось от перечисленного выше.

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

 public void CheckUsersCount(CompanyProduct companyProduct) 
 {
     companyProduct.Name = "Test";
 }

Использовать этот:

 public void CheckUsersCount(Guid companyProductId)
 {
      CompanyProduct companyProduct = CompanyProductManager.Get(companyProductId);
      companyProduct.Name = "Test";
 }
0
Tanyo Ivanov

Используя решение Slauma, я создал несколько общих функций, чтобы помочь обновить дочерние объекты и коллекции дочерних объектов.

Все мои постоянные объекты реализуют этот интерфейс

/// <summary>
/// Base interface for all persisted entries
/// </summary>
public interface IBase
{
    /// <summary>
    /// The Id
    /// </summary>
    int Id { get; set; }
}

С этим я реализовал эти две функции в моем репозитории

    /// <summary>
    /// Check if orgEntry is set update it's values, otherwise add it
    /// </summary>
    /// <param name="set">The collection</param>
    /// <param name="entry">The entry</param>
    /// <param name="orgEntry">The original entry found in the database (can be <code>null</code> is this is a new entry)</param>
    /// <returns>The added or updated entry</returns>
    public T AddOrUpdateEntry<T>(DbSet<T> set, T entry, T orgEntry) where T : class, IBase
    {
        if (entry.Id == 0 || orgEntry == null)
        {
            entry.Id = 0;
            return set.Add(entry);
        }
        else
        {
            Context.Entry(orgEntry).CurrentValues.SetValues(entry);
            return orgEntry;
        }
    }

    /// <summary>
    /// check if each entry of the new list was in the orginal list, if found, update it, if not found add it
    /// all entries found in the orignal list that are not in the new list are removed
    /// </summary>
    /// <typeparam name="T">The type of entry</typeparam>
    /// <param name="set">The database set</param>
    /// <param name="newList">The new list</param>
    /// <param name="orgList">The original list</param>
    public void AddOrUpdateCollection<T>(DbSet<T> set, ICollection<T> newList, ICollection<T> orgList) where T : class, IBase
    {
        // attach or update all entries in the new list
        foreach (T entry in newList)
        {
            // Find out if we had the entry already in the list
            var orgEntry = orgList.SingleOrDefault(e => e.Id != 0 && e.Id == entry.Id);

            AddOrUpdateEntry(set, entry, orgEntry);
        }

        // Remove all entries from the original list that are no longer in the new list
        foreach (T orgEntry in orgList.Where(e => e.Id != 0).ToList())
        {
            if (!newList.Any(e => e.Id == orgEntry.Id))
            {
                set.Remove(orgEntry);
            }
        }
    }

Чтобы использовать это, я делаю следующее:

var originalParent = _dbContext.ParentItems
    .Where(p => p.Id == parent.Id)
    .Include(p => p.ChildItems)
    .Include(p => p.ChildItems2)
    .SingleOrDefault();

// Add the parent (including collections) to the context or update it's values (except the collections)
originalParent = AddOrUpdateEntry(_dbContext.ParentItems, parent, originalParent);

// Update each collection
AddOrUpdateCollection(_dbContext.ChildItems, parent.ChildItems, orgiginalParent.ChildItems);
AddOrUpdateCollection(_dbContext.ChildItems2, parent.ChildItems2, orgiginalParent.ChildItems2);

Надеюсь это поможет


ДОПОЛНИТЕЛЬНО: Вы также можете создать отдельный класс DbContextExtentions (или ваш собственный контекстный интерфейс):

public static void DbContextExtentions {
    /// <summary>
    /// Check if orgEntry is set update it's values, otherwise add it
    /// </summary>
    /// <param name="_dbContext">The context object</param>
    /// <param name="set">The collection</param>
    /// <param name="entry">The entry</param>
    /// <param name="orgEntry">The original entry found in the database (can be <code>null</code> is this is a new entry)</param>
    /// <returns>The added or updated entry</returns>
    public static T AddOrUpdateEntry<T>(this DbContext _dbContext, DbSet<T> set, T entry, T orgEntry) where T : class, IBase
    {
        if (entry.IsNew || orgEntry == null) // New or not found in context
        {
            entry.Id = 0;
            return set.Add(entry);
        }
        else
        {
            _dbContext.Entry(orgEntry).CurrentValues.SetValues(entry);
            return orgEntry;
        }
    }

    /// <summary>
    /// check if each entry of the new list was in the orginal list, if found, update it, if not found add it
    /// all entries found in the orignal list that are not in the new list are removed
    /// </summary>
    /// <typeparam name="T">The type of entry</typeparam>
    /// <param name="_dbContext">The context object</param>
    /// <param name="set">The database set</param>
    /// <param name="newList">The new list</param>
    /// <param name="orgList">The original list</param>
    public static void AddOrUpdateCollection<T>(this DbContext _dbContext, DbSet<T> set, ICollection<T> newList, ICollection<T> orgList) where T : class, IBase
    {
        // attach or update all entries in the new list
        foreach (T entry in newList)
        {
            // Find out if we had the entry already in the list
            var orgEntry = orgList.SingleOrDefault(e => e.Id != 0 && e.Id == entry.Id);

            AddOrUpdateEntry(_dbContext, set, entry, orgEntry);
        }

        // Remove all entries from the original list that are no longer in the new list
        foreach (T orgEntry in orgList.Where(e => e.Id != 0).ToList())
        {
            if (!newList.Any(e => e.Id == orgEntry.Id))
            {
                set.Remove(orgEntry);
            }
        }
    }
}

и используйте это как:

var originalParent = _dbContext.ParentItems
    .Where(p => p.Id == parent.Id)
    .Include(p => p.ChildItems)
    .Include(p => p.ChildItems2)
    .SingleOrDefault();

// Add the parent (including collections) to the context or update it's values (except the collections)
originalParent = _dbContext.AddOrUpdateEntry(_dbContext.ParentItems, parent, originalParent);

// Update each collection
_dbContext.AddOrUpdateCollection(_dbContext.ChildItems, parent.ChildItems, orgiginalParent.ChildItems);
_dbContext.AddOrUpdateCollection(_dbContext.ChildItems2, parent.ChildItems2, orgiginalParent.ChildItems2);
0
Bluemoon74

Эта проблема возникает из-за того, что мы пытаемся удалить родительскую таблицу, при этом данные дочерней таблицы присутствуют . Мы решаем проблему с помощью каскадного удаления.

В модели Create метод в классе dbcontext.  

 modelBuilder.Entity<Job>()
                .HasMany<JobSportsMapping>(C => C.JobSportsMappings)
                .WithRequired(C => C.Job)
                .HasForeignKey(C => C.JobId).WillCascadeOnDelete(true);
            modelBuilder.Entity<Sport>()
                .HasMany<JobSportsMapping>(C => C.JobSportsMappings)
                  .WithRequired(C => C.Sport)
                  .HasForeignKey(C => C.SportId).WillCascadeOnDelete(true);

После этого в нашем API Call

var JobList = Context.Job                       
          .Include(x => x.JobSportsMappings)                                     .ToList();
Context.Job.RemoveRange(JobList);
Context.SaveChanges();

Каскадное удаление опция удаляет родительскую, а также родительскую дочернюю таблицу с помощью этого простого кода. Попробуй так просто.

Удалить диапазон, который используется для удаления списка записей в базе данных Спасибо

0
Sowmiya V

Я столкнулся с той же проблемой, когда собирался удалить свою запись, чем возникла какая-то проблема, потому что решение этой проблемы заключается в том, что когда вы собираетесь удалить свою запись, чем вы что-то упустили перед удалением заголовка/основной записи, вы должны написать в код удалите его детали перед заголовком/Master Я надеюсь, что ваш вопрос будет решен.

0
Ghazi Hur