Сущности, ссылающиеся на себя. Ошибка сохранения изменений! Я что-то упускаю?C#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Сущности, ссылающиеся на себя. Ошибка сохранения изменений! Я что-то упускаю?

Сообщение Anonymous »

У меня есть сущность

Код: Выделить всё

public class ExpenseCategory
{
public int Id { get; set; }
public string Label { get; set; } = string.Empty;

public int? ParentId { get; set; }
public ExpenseCategory? Parent { get; set; }

public int? PreviousSiblingId { get; set; }
public ExpenseCategory? PreviousSibling { get; set; }

public int? NextSiblingId { get; set; }
public ExpenseCategory? NextSibling { get; set; }

public List Children { get; set; } = [];

public List Expenses { get; set; } = [];
}

в моем DbContext у меня есть

Код: Выделить всё

        modelBuilder.Entity().ToTable("ExpenseCategory")
.HasOne(e => e.Parent)
.WithMany(e => e.Children)
.HasForeignKey(e => e.ParentId)
.OnDelete(DeleteBehavior.Restrict); // Prevents cascading deletes

// Configuring the ExpenseCategory entity
modelBuilder.Entity()
.HasKey(ec => ec.Id);

modelBuilder.Entity()
.Property(ec => ec.Label)
.IsRequired(); // Ensure Label is required

modelBuilder.Entity()
.HasOne(e => e.PreviousSibling)
.WithOne()
.HasForeignKey(e => e.PreviousSiblingId)
.OnDelete(DeleteBehavior.Restrict);

modelBuilder.Entity()
.HasOne(e => e.NextSibling)
.WithOne()
.HasForeignKey(e => e.NextSiblingId)
.OnDelete(DeleteBehavior.Restrict);

в коде форм у меня есть

Код: Выделить всё

    private void AddRootButton_Click(object sender, EventArgs e)
{
var label = GetNewCategoryLabel();
if (label.IsNullOrEmpty()) return;

ExpenseCategory? prevCategory = null;

TreeNode? prevNode = null;
var rootNodes = TV.Nodes;
if (rootNodes.Count > 0)
{
prevNode = rootNodes[rootNodes.Count - 1];
if (prevNode != null)
{
prevCategory = (ExpenseCategory)prevNode.Tag;
}
}

// Create new category
var newCategory = new ExpenseCategory()
{
Label = label,
Parent = null,
PreviousSibling = prevCategory,
NextSibling = null, // Initially null
Children = [],
Expenses = []
};

// Add new category to the context
var entry = _context.ExpenseCategories.Add(newCategory);

// Setup sibling references conditionally
if (prevCategory != null)
{
// Set the NextSibling of the previous category to the new one
prevCategory.NextSibling = entry.Entity;
entry.Entity.PreviousSibling = prevCategory;  // Establish mutual reference
}
else
{
// If there's no previous category, we can explicitly set null to avoid confusion
entry.Entity.PreviousSibling = null;
}

// Add the new node to the TreeView
TreeNode newNode = new TreeNode(newCategory.Label)
{
Tag = newCategory
};

var index = TV.Nodes.Add(newNode);
TV.SelectedNode = TV.Nodes[index];
ActiveControl = TV;

// Note: _context.SaveChanges() will be called later
}

Поскольку я хочу, чтобы _context сохранял изменения при закрытии формы, а не при вводе новой записи,
Я вызываю это

Код: Выделить всё

   private async void ExpenseCategoriesDialog_FormClosing(object sender, FormClosingEventArgs e)
{

await SaveChangesWithTrackingChecksAsync();
}

Код: Выделить всё

private async Task SaveChangesWithTrackingChecksAsync()
{
try
{
foreach (var entry in _context.ChangeTracker.Entries())
{
var category = entry.Entity;
Debug.WriteLine($"Entity: {category.Label}, State: {entry.State}");

// Check PreviousSibling and NextSibling presence and tracking status
if (category.PreviousSibling != null)
{
var previousSiblingEntry = _context.ChangeTracker.Entries().FirstOrDefault(e => e.Entity == category.PreviousSibling);
if (previousSiblingEntry == null)
{
Debug.WriteLine($"    PreviousSibling (Label: {category.PreviousSibling.Label}, Id: {category.PreviousSibling.Id}) is NOT being tracked. Attaching it now.");
_context.Attach(category.PreviousSibling);
}
else
{
Debug.WriteLine($"    PreviousSibling (Label: {category.PreviousSibling.Label}, Id: {category.PreviousSibling.Id}) is being tracked.");
}
}
else
{
Debug.WriteLine("    PreviousSibling is null.");
}

if (category.NextSibling != null)
{
var nextSiblingEntry = _context.ChangeTracker.Entries().FirstOrDefault(e => e.Entity == category.NextSibling);
if (nextSiblingEntry == null)
{
Debug.WriteLine($"    NextSibling (Label: {category.NextSibling.Label}, Id: {category.NextSibling.Id}) is NOT being tracked.  Attaching it now.");
_context.Attach(category.NextSibling);
}
else
{
Debug.WriteLine($"    NextSibling (Label: {category.NextSibling.Label}, Id: {category.NextSibling.Id}) is being tracked.");
}
}
else
{
Debug.WriteLine("    NextSibling is null.");
}

// Additional check to verify sibling chain integrity
if (category.NextSibling?.PreviousSibling != category)
{
Debug.WriteLine($"Warning: {category.Label}'s NextSibling ({category.NextSibling?.Label}) does not reference {category.Label} as PreviousSibling.");
}

if (category.PreviousSibling?.NextSibling != category)
{
Debug.WriteLine($"Warning: {category.Label}'s PreviousSibling ({category.PreviousSibling?.Label}) does not reference {category.Label} as NextSibling.");
}
}

await _context.SaveChangesAsync();
}
catch (NullReferenceException ex)
{
Debug.WriteLine("NullReferenceException encountered: " + ex.Message);
throw;
}
}
Когда я добавляю 1 и 2 в качестве входных записей при нажатии SaveChangesAsync, я получаю

Код: Выделить всё

System.NullReferenceException: 'Object reference not set to an instance of an object.'
в окне вывода я получаю

Код: Выделить всё

Entity: 1, State: Added
PreviousSibling is null.
NextSibling (Label: 2, Id: 0) is being tracked.
Warning: 1's PreviousSibling () does not reference 1 as NextSibling.
Entity: 2, State: Added
PreviousSibling (Label: 1, Id: 0) is being tracked.
NextSibling is null.
Warning: 2's NextSibling () does not reference 2 as PreviousSibling.
Exception thrown: 'System.NullReferenceException' in System.Private.CoreLib.dll
Object reference not set to an instance of an object.

Как видите, хотя ссылки назначены правильно, я продолжаю получать это исключение и не могу понять, является ли это ошибкой EFCore или я что-то упускаю!!!
Также

Код: Выделить всё

Warning: 1's PreviousSibling () does not reference 1 as NextSibling.
и

Код: Выделить всё

Warning: 2's NextSibling () does not reference 2 as PreviousSibling.
недействительны, так как параметр previousSibling для 1 имеет значение NULL, поэтому для NextSibling для 1 нет элемента NextSibling
а также параметр NextSibling для 2 также имеет значение NULL, поэтому для NextSibling для 2 также нет значения NextSibling< /p>
Записи сохраняются правильно, если я вызываю SaveChanges после каждого ввода записи!
Можете ли вы помочь, пожалуйста, поскольку я потратил часы, пытаясь выяснить, почему EFCore не может сохранить такие простые отношения данные!!
Заранее спасибо
Я показал вам выше, что я пробовал до сих пор.
Только когда savechanges вызывается сразу после добавления новой записи, работает хорошо
В противном случае, когда форма закрывается, я всегда получаю исключение. Ссылка на объект не установлена ​​на экземпляр объекта, и я не могу выяснить, какая ссылка на объект не установлена ​​на экземпляр объекта

Подробнее здесь: https://stackoverflow.com/questions/791 ... -something
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C#»