繁体   English   中英

实体框架 (EF) 和 .Net 6 Blazor 不更新数据库

[英]Entity Framework (EF) and .Net 6 Blazor not updating database

我需要帮助试图了解为什么我的 .net Core 6 中的 Blazor(服务器端)组件在删除实体时没有更新我的数据库,请查看我的代码示例:(事先,感谢您的所有帮助!)

首先,我按如下方式注入我的数据库上下文:

@inject AppDbContext db

然后,在我的代码下面,我决定查询一些数据,在这种情况下,客户如下:

 @code {

   private List<Customer> clients { get; set; }

 protected override async Task OnInitializedAsync()
 {
     clients = await db.Customers.ToListAsync();
 }

}

现在,我创建了一个带有删除客户方法的按钮; 首先我搜索实体,如果找到,然后我从数据库中的“客户”列表中删除该项目,如下所示:

private async Task DeleteCustomer(int CustomerId)
 {    
     Customer? customer = clients.FirstOrDefault(f => f.Id == CustomerId);

     if (customer is not null)
     {           
         clients.Remove(customer);
         await db.SaveChangesAsync();
     }

 }

问题是实体已从列表中删除但未从数据库中删除,因此当我刷新仍在那里的项目时,我必须在 if 中应用另一个命令以使其工作:

db.Remove(customer);

换句话说,我必须将它从客户列表和列表中删除,使工作加倍,在我看来它完全失去了来自数据库和数据库的列表之间的连接(或引用)。 这是我第一次看到这样的东西,我错过了什么吗? 我是否按照我应该做的方式使用 EF? 我可以添加该命令并使其工作,但我认为这不是一个好习惯,请帮助!

是的,那是因为这就是 EF 的工作方式。

客户端列表包含查询的元素。 即使删除后,它仍然是一个查询元素。 Ef 没有合乎逻辑的方法来更新客户端 - 特别是因为客户端是一个列表,它没有以合理的方式为此提供 API。

因此,您必须将其从两者中删除,这是合乎逻辑的。

其实你完全错了。 从客户端删除某些内容不会从 Ef 触发任何内容,因为开始没有任何意义。 我可以将它们删除然后在上面运行代码 - 并且会触发从数据库中自动删除只是为了在 UI 中过滤掉一些东西。 只有 db.Remove 实际上告诉 Ef 它是从数据库中删除它。 这不是双重的,是 Ef 没有神奇地读懂你的思想。

您必须从 dbcontext 中删除项目,而不是从列表中删除。 创建视图后,所有 dbcontext 都已处理,列表未连接。 当您尝试删除时,您已经拥有不同的数据库上下文。 所以你需要这个

public async Task DeleteCustomer(int CustomerId)
 {    
     var customer = await db.Customers.FirstOrDefaultAsync(f => f.Id == CustomerId);

     if (customer!=null)
     {           
        db.Customers.Remove(customer);
       var result=  await db.SaveChangesAsync();
     }

 }

您需要使用dbcontext factory ,如下所示:

services.AddDbContextFactory<ContactContext>(opt =>
                opt.UseSqlite($"Data Source={nameof(ContactContext.ContactsDb)}.db")
                .EnableSensitiveDataLogging());

ContactContext.cs

/// <summary>
    /// Context for the contacts database.
    /// </summary>
    public class ContactContext : DbContext
    {
        /// <summary>
        /// Magic string.
        /// </summary>
        public static readonly string RowVersion = nameof(RowVersion);

        /// <summary>
        /// Magic strings.
        /// </summary>
        public static readonly string ContactsDb = nameof(ContactsDb).ToLower();

        /// <summary>
        /// Inject options.
        /// </summary>
        /// <param name="options">The <see cref="DbContextOptions{ContactContext}"/>
        /// for the context
        /// </param>
        public ContactContext(DbContextOptions<ContactContext> options)
            : base(options)
        {
            Debug.WriteLine($"{ContextId} context created.");
        }

        /// <summary>
        /// List of <see cref="Contact"/>.
        /// </summary>
        public DbSet<Contact> Contacts { get; set; }

        /// <summary>
        /// Define the model.
        /// </summary>
        /// <param name="modelBuilder">The <see cref="ModelBuilder"/>.</param>
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            // this property isn't on the C# class
            // so we set it up as a "shadow" property and use it for concurrency
            modelBuilder.Entity<Contact>()
                .Property<byte[]>(RowVersion)
                .IsRowVersion();

            base.OnModelCreating(modelBuilder);
        }

        /// <summary>
        /// Dispose pattern.
        /// </summary>
        public override void Dispose()
        {
            Debug.WriteLine($"{ContextId} context disposed.");
            base.Dispose();
        }

        /// <summary>
        /// Dispose pattern.
        /// </summary>
        /// <returns>A <see cref="ValueTask"/></returns>
        public override ValueTask DisposeAsync()
        {
            Debug.WriteLine($"{ContextId} context disposed async.");
            return base.DisposeAsync();
        }
    }

假设您有一个索引页面,您可以在其中显示联系人列表:

@inject IDbContextFactory<ContactContext> DbFactory

@code 
{
    protected async override Task OnInitializedAsync()
    {
       // When the Index page is created the ReloadAsync method 
       // is called to retrieve a list of contact objects
    }

    // When you delete a contact, it is removed both from the database
    // and from the list that hold the contacts
    private async Task DeleteContactAsync()
    {
        using var context = DbFactory.CreateDbContext();

        Filters.Loading = true;

        var contact = await context.Contacts.FirstAsync(
            c => c.Id == Wrapper.DeleteRequestId);

        if (contact != null)
        {
            context.Contacts.Remove(contact);
            await context.SaveChangesAsync();
        }

        Filters.Loading = false;

        await ReloadAsync();
    }

    
 

    private async Task ReloadAsync()
        {
            if (Filters.Loading || Page < 1)
            {
                return;
            }
    
            Filters.Loading = true;
    
            if (Wrapper != null)
            {
                Wrapper.DeleteRequestId = 0;
            }
    
            Contacts = null;
    
            using var context = DbFactory.CreateDbContext();
    
            // run the query to load the current page
            Contacts = await 
            QueryAdapter.FetchAsync(context.Contacts.AsQueryable());
    
            // now we're done
            Filters.Loading = false;
        }
    }

注意:这就是我们在 Blazor 中编码的方式。 最重要的特性是 Blazor 组件模型……重新渲染无处不在。 每次添加删除或更新联系人对象时,您都需要创建一个新的数据库上下文,执行操作,然后让它消失并更新您的联系人存储(在内存列表中)

请复制上面的内容,因为我很快就会删除它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM