Код: Выделить всё
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; } = [];
}
Код: Выделить всё
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
}
Я вызываю это
Код: Выделить всё
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;
}
}
Код: Выделить всё
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.
Также
Код: Выделить всё
Warning: 1's PreviousSibling () does not reference 1 as NextSibling.
Код: Выделить всё
Warning: 2's NextSibling () does not reference 2 as PreviousSibling.
а также параметр NextSibling для 2 также имеет значение NULL, поэтому для NextSibling для 2 также нет значения NextSibling< /p>
Записи сохраняются правильно, если я вызываю SaveChanges после каждого ввода записи!
Можете ли вы помочь, пожалуйста, поскольку я потратил часы, пытаясь выяснить, почему EFCore не может сохранить такие простые отношения данные!!
Заранее спасибо
Я показал вам выше, что я пробовал до сих пор.
Только когда savechanges вызывается сразу после добавления новой записи, работает хорошо
В противном случае, когда форма закрывается, я всегда получаю исключение. Ссылка на объект не установлена на экземпляр объекта, и я не могу выяснить, какая ссылка на объект не установлена на экземпляр объекта
Подробнее здесь: https://stackoverflow.com/questions/791 ... -something