我有一个Blazor页面如下:
@inject IDbContextFactory<MyContext> DbFactory
<EditForm EditContext="@editContext" OnSubmit="@Submit" FormName="create">
...
...
...
<button type="submit" class="w-100 btn btn-lg btn-primary">Create</button>
</EditForm>
@code
{
...
private async Task Submit()
{
using var dbcontext = DbFactory.CreateDbContext();
MyObject c = new MyObject
{
MyMember1="abc",
MyMember2="123"
};
dbcontext.MyObjects.Add(c);
await dbcontext.SaveChangesAsync();
}
}
字符串
在Program.cs
中,工厂是这样声明的:
builder.Services.AddDbContextFactory<MyContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("BlazorAppContext") ?? throw new InvalidOperationException("Connection string 'BlazorAppContext' not found.")));
型MyObject
声明如下:
public class MyBaseObject
{
public Int32 Id { get; set; }
public string? MyMember1{ get; set; }
public string? MyMember2 { get; set; }
public MyBaseObject()
{
}
public MyBaseObject(MyBaseObject mybaseObject)
{
MyMember1 = mybaseObject.MyMember1;
MyMember2 = mybaseObject.MyMember2;
}
public void AssignBase(MyBaseObject mybaseObject)
{
MyMember1 = mybaseObject.MyMember1;
MyMember2 = mybaseObject.MyMember2;
}
}
public class MyObject : MyBaseObject
{
public MyObject() : base()
{
}
public MyObject(MyBaseObject baseobject) : base(baseobject)
{
}
}
型
在将c添加到dbcontext.MyObjects
之前,已正确创建对象“c”,MyObjects
包含从SQL Server Express数据库正确获取的两个对象。
在Add(c)
之后,dbcontext.MyObjects
的内容与之前完全相同,因此只有两个对象。似乎dbcontext
忽略了Add
语句或者它是只读的。
在DatabaseInitiator
类中,它工作得很好,数据库正确地填充了初始数据。
我希望dbcontext.MyObjects
拥有三个元素,并在现有的两个元素上添加'c',但这并没有发生。
那么,为什么Blazor页面中的dbcontext
似乎是只读的?
谢谢你们
**编辑:**看来我已经解决了,我在SaveChanges
之前加了dbcontext.Entry(Model.CurrentUser).State = EntityState.Unchanged;
。但我真的不明白为什么一个用户会被改变。我没有在Users上做任何改变。特别感谢@StevePy,他让我走上了正确的道路。
1条答案
按热度按时间rslzwgfq1#
关于
SaveChanges
上的PK违规:这通常是由以下两种情况之一引起的:未设置为作为标识操作的PK,并且在代码中没有被赋予唯一ID,或者试图使用这些相关实体的未跟踪副本将引用关联到现有行。身份PK
默认情况下,大多数数据库提供程序(& EF)将识别名为“Id”或“{name}Id”/"{name}_Id”的
int
/long
属性(即MyObjectId)作为标识列,这些标识列将在保存时由数据库填充。但是,某些数据库,例如-内存数据库不提供此功能,因此Identity行为被忽略。当它尝试插入ID为0,其中已存在具有该ID的行。如果您使用的是非常规PK名称,如“MyObjectKey”,则需要将其标识为PK和标识列。由于您的名称为“ID”,因此只要您使用的数据库支持标识列,就不应该是这种情况。未跟踪的引用
这将涉及到创建一个新的MyObject,它引用了另一个现有的实体。例如,如果MyObject引用了一个Status,它是一个指向Statuses查找表的实体,并且您执行了以下操作:
字符串
这将导致PK错误。虽然您可能只打算插入MyObject并引用ID为1的现有Status“New”/,但DbContext不会跟踪该状态,因此它将被解释为new。这包括您可能将Status“实体”传递到此方法的情况,例如从Web客户端返回的引用。
相反,您希望确保对DB中现有记录的任何引用首先由DbContext加载和跟踪。这确保它知道将新实体关联到现有引用,而不是尝试插入新引用:
型