asp.net 为什么在我的blazor页面中,dbcontext似乎变成了只读?

uhry853o  于 5个月前  发布在  .NET
关注(0)|答案(1)|浏览(91)

我有一个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,他让我走上了正确的道路。

rslzwgfq

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查找表的实体,并且您执行了以下操作:

using var dbcontext = DbFactory.CreateDbContext();

MyObject c = new MyObject
{
    MyMember1="abc",
    MyMember2="123", 
    Status = new Status { StatusId == 1 } // "New" status
};

dbcontext.MyObjects.Add(c);

await dbcontext.SaveChangesAsync();

字符串
这将导致PK错误。虽然您可能只打算插入MyObject并引用ID为1的现有Status“New”/,但DbContext不会跟踪该状态,因此它将被解释为new。这包括您可能将Status“实体”传递到此方法的情况,例如从Web客户端返回的引用。
相反,您希望确保对DB中现有记录的任何引用首先由DbContext加载和跟踪。这确保它知道将新实体关联到现有引用,而不是尝试插入新引用:

var status = dbContext.Statuses.Single(x => x.StatusId == 1); // "New status"
MyObject c = new MyObject
{
    MyMember1="abc",
    MyMember2="123", 
    Status = status
};

相关问题