有一个数据上下文类ApplicationContext.cs
:
internal class ApplicationContext : DbContext
{
public DbSet<Contact>? Contacts { get; set; }
public DbSet<PhoneType>? PhoneTypes { get; set; }
public DbSet<ContactInfo>? ContactsInfo { get; set; }
public ApplicationContext() : base("Data Source=XXX;Initial Catalog=ContactsNotebookDB;Integrated Security=True;TrustServerCertificate=True")
{
Database.CreateIfNotExists();
}
}
记录详情:
Contact.cs
:
internal class Contact : IDatabase
{
public required int ID { get; set; }
public required string PhoneNumber { get; set; }
public int? PhoneTypeID { get; set; }
public required int ContactInfoID { get; set; }
}
ContactInfo.cs
:
[Table("ContactsInfo")] // обязательное явное указание названия таблицы
(по умолчанию EF читает как "ContactInfoes")
internal class ContactInfo : IDatabase
{
public required int ID { get; set; }
public required string Name { get; set; }
public required string Surname { get; set; }
public string? Patronymic { get; set; }
public required char Sex { get; set; }
}
当我尝试在其中之一的代码中保存数据View
时,发生异常:
using ApplicationContext ApplicationContext = new();
int ContactsInfoMaxID = ApplicationContext.ContactsInfo.Count();
int ContactsMaxID = ApplicationContext.Contacts.Count();
ContactInfo ContactInfo = new()
{
ID = ContactsInfoMaxID + 1,
Name = NameTextBox.Text,
Surname = SurnameTextBox.Text,
Patronymic = Patronymic,
Sex = SexComboBox.Text[0]
};
Contact Contact = new()
{
ID = ContactsMaxID + 1,
PhoneNumber = PhoneNumberTextBox.Text,
PhoneTypeID = PhoneTypeComboBox.SelectedIndex,
ContactInfoID = ContactInfo.ID,
};
ApplicationContext.ContactsInfo.Add(ContactInfo);
ApplicationContext.Contacts.Add(Contact);
ApplicationContext.SaveChanges(); // тут возникает исключение при сохранении
该行ApplicationContext.SaveChanges();
抛出以下异常:
System.Data.Entity.Infrastructure.DbUpdateException: "An error occurred while updating the entries. See the inner exception for details."
还有 2 个内部异常:
UpdateException: An error occurred while updating the entries. See the inner exception for details.
SqlException: Не удалось вставить значение NULL в столбец "ID", таблицы "ContactsNotebookDB.dbo.Contacts"; в столбце запрещены значения NULL. Ошибка в INSERT.
Выполнение данной инструкции было прервано.
问题更新:
当您尝试从数据库中删除记录时,也会发生异常。
包含尝试删除数据ViewModel
的方法的代码片段:
/// <summary>
/// Команда удаления контакта
/// </summary>
/// <param name="parameter"></param>
private void DeleteContact(object parameter)
{
MessageBoxResult DeleteContactMessageBoxResult = MessageBox.Show($"Внимание, вы действительно хотите удалить следующий контакт:\n\n{PhoneNumber}\n{Surname} {Name}{(Patronymic == "—" ? null : " " + Patronymic)}?", "Удаление контакта", MessageBoxButton.YesNo, MessageBoxImage.Warning);
if (DeleteContactMessageBoxResult == MessageBoxResult.Yes)
{
using ApplicationContext ApplicationContext = new();
bool IsContactInUse = ApplicationContext.Contacts.Any(Contact => Contact.ContactInfoID == ID);
if (!IsContactInUse)
{
ApplicationContext.ContactsInfo?.Remove(ContactInfo);
}
else
{
Console.WriteLine("Текущий используется в Contact и не может быть удален.");
}
ApplicationContext.Contacts?.Remove(Contact);
ApplicationContext.SaveChanges();
}
}
该行ApplicationContext.Contacts?.Remove(Contact);
抛出异常:
System.InvalidOperationException: "The object cannot be deleted because it was not found in the ObjectStateManager."
附加信息:
已经很奇怪的是,ContactsInfo
它只返回 1 条新记录,而Contacts
它返回所有记录 + 一条新记录(顺便说一下,由于某种原因它被放置在表的顶部)。
即使我显式设置Null-данные
,该条目仍然不会输入数据库,显示相同的异常。
PS我在添加的条目Contacts
(属性PhoneTypeID
)中看到0,我将其更正为1,但这并没有影响错误。
debug 中的表达式
ApplicationContext.ContactsInfo.Sql
返回值:SELECT [范围 1].[ID] AS [ID]、[范围 1].[名称] AS [名称]、[范围 1].[姓氏] AS [姓氏]、[范围 1].[父名] AS [父名] FROM [ dbo].[联系人信息] AS [范围 1]
Sex
也就是说,由于某种原因,数据库表中缺少一列。
我重新创建了数据库,创建了一个没有记录、没有关系的重复数据库,它没有主键和必填字段,但在这种情况下会引发另一个异常:
System.Data.Entity.Infrastruct.DbUpdateConcurrencyException:“存储更新、插入或删除语句影响了意外数量的行 (0)。自加载实体以来,实体可能已被修改或删除。请参阅http://go.microsoft。 com/fwlink/?LinkId=472540了解有关理解和处理乐观并发异常的信息。”
和内部:
OptimisticConcurrencyException: Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=472540 for information on understanding and handling optimistic concurrency exceptions.
- MS SQL 数据库中的表结构:
ContactsInfo
:
Contacts
:
如果您尝试添加条目而不是添加到
Contacts
,而是添加到ContactsInfo
并尝试保存更改,则会发生相同的异常,但具有不同的内部异常:SqlException:无法将 NULL 值插入表“ContactsNotebookDB.dbo.ContactsInfo”的列“Sex”;列中不允许有 NULL 值。插入错误。该指令被中止。
而且,好吧,从显而易见的角度来看,它当然
ApplicationContext
从数据库接收数据,因为它在访问它时返回正确的值(表及其记录的数量),所以问题不在于连接。
更新:
- 目前尚不清楚为什么该行
ApplicationContext.Contacts?.Remove(Contact);
会导致异常,因为联系人数据库中的数据已加载到ApplicationContext
(尽管调试中的检查工作正常:它要么显示已加载Contacts
,要么写入其编号为 0)。
@Alexander Petrov在评论中的建议:
正中目标!但我将此作为建议,但我从未想过这是解决这个问题的唯一方法。顺便说一句,当我第一次使用它时,由于某种原因我无法解决问题。
奇怪的是,我将从修复从数据库中删除记录的功能开始,因为它更容易。
为此,您只需在使用 删除之前使用 方法附加要删除的记录。
Attach()
Remove()
例如:
但
Attach()
只有在以下情况下才需要:也就是说,如果该对象是通过当前上下文(通过
Find
、FirstOrDefault
等方法)从数据库获取的,那么在这种情况下该对象已被跟踪,并且不需要LINQ-запросы
使用该方法。Attach()
就这样。这足以删除条目。并且没有像将主键更改为自动递增键那样“敲着手鼓跳舞”。我并不是说自动递增键不好。我只是说
Remove()
至少提供了选择的自由。我会立即说答案是从这里获取的:https://stackoverflow.com/questions/7791149/the-object-cannot-be-deleted-because-it-was-not-found-in-the-对象状态管理器。
Add()
使用...方法向数据库添加记录则不能说同样的情况。为了能够在数据库中创建新条目,您需要......不,不是更改代码,而是更改数据库中的体系结构。
即向key指示
ID
它是自增的。就这样!即在表project中,修改
MS SQL
字段参数ID
如下:代码的最终版本:
更新: 重要!请注意,如果您有一个从属实体(在本例中,我有一个依赖于 y 的属性
ContactInfoID
y),那么在将新记录添加到数据库之前,您需要一一保存实体:Contact
ID
ContactInfo
因为在初始化时
ID
y 是ContactInfo
相等的0
-ID
只有在添加到数据库后才会对其进行赋值!如果在数据库中设置了外键限制,这一点尤其明显: