Простое веб-приложение Blazor, созданное в VS2022 с использованием шаблона приложения wb, для редактирования записи поставщика. Все работает, и я могу редактировать запись в одновременных вкладках браузера.
Я видел примеры использования DbContext DI на SO, но они не предлагают доступ Intellisense к теневым свойствам в классе DbContext моего приложения.
Итак, я использовал подход (см. код), при котором я внедряю контекст базы данных своего приложения.
В частности, мне было интересно, вызовет ли внедрение моего класса LicensingContext для получения доступа Intellisense к теневым свойствам DbSets неприятные проблемы или это будет неэффективно? и почему.
Кажется, что контекст создан и расположен соответствующим образом.
LicensingContext (мой класс App DbContext)
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
#nullable disable
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
namespace Licensing.Models;
public partial class LicensingContext : Microsoft.EntityFrameworkCore.DbContext
{
DateTime dt = DateTime.Now;
public LicensingContext(DbContextOptions<LicensingContext> options)
: base(options)
{
Console.WriteLine(string.Format("+++ Licensing context CREATED {0}", dt));
}
~LicensingContext()
{
Console.WriteLine(string.Format("--- Licensing context DESTROYED {0}", dt));
}
public virtual DbSet<Allocations> Allocations { get; set; }
public virtual DbSet<Dates> Dates { get; set; }
public virtual DbSet<Departments> Departments { get; set; }
public virtual DbSet<VendorBundles> VendorBundles { get; set; }
public virtual DbSet<VendorLicenceModules> VendorLicenceModules { get; set; }
public virtual DbSet<Vendors> Vendors { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Allocations>(entity =>
{
entity.HasKey(e => e.pkId).HasName("PK_fctAllocation_1");
entity.HasOne(d => d.Department).WithMany(p => p.Allocations).HasConstraintName("FK_fctAllocation_dimDepartment");
entity.HasOne(d => d.VendorBundle).WithMany(p => p.Allocations)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_fctAllocation_dimVendorBundle");
entity.HasOne(d => d.Vendor).WithMany(p => p.Allocations).HasConstraintName("FK_fctAllocation_dimVendor");
entity.HasOne(d => d.VendorLicenceModule).WithMany(p => p.Allocations)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_fctAllocation_dimVendorLicenceModule");
});
modelBuilder.Entity<Dates>(entity =>
{
entity.HasKey(e => e.pkId).HasName("PK_dimDates");
entity.Property(e => e.MMYYYY).IsFixedLength();
entity.Property(e => e.Style101).IsFixedLength();
entity.Property(e => e.Style103).IsFixedLength();
entity.Property(e => e.Style112).IsFixedLength();
entity.Property(e => e.Style120).IsFixedLength();
entity.Property(e => e.TheDaySuffix).IsFixedLength();
});
modelBuilder.Entity<Departments>(entity =>
{
entity.HasKey(e => e.pkId).HasName("PK_dimDepartment");
entity.Property(e => e.Notes).IsFixedLength();
});
modelBuilder.Entity<VendorBundles>(entity =>
{
entity.HasKey(e => e.pkId).HasName("PK_dimVendorBundle");
entity.HasOne(d => d.VendorFkNavigation).WithMany(p => p.VendorBundles).HasConstraintName("FK_dimVendorBundle_dimVendor");
});
modelBuilder.Entity<VendorLicenceModules>(entity =>
{
entity.HasKey(e => e.pkId).HasName("PK_dimLicenceModules");
entity.HasOne(d => d.Bundle).WithMany(p => p.VendorLicenceModules).HasConstraintName("FK_dimVendorLicenceModule_dimVendorBundle");
});
modelBuilder.Entity<Vendors>(entity =>
{
entity.HasKey(e => e.pkId).HasName("PK_dimVendor_1");
});
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}
VendorDetails (родительский класс)
@* @page "/Vendors/createedit" *@
@* using System;
using System.Linq;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.JSInterop;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Web; *@
@* using Microsoft.AspNetCore.Identity; *@
@using Microsoft.EntityFrameworkCore
@using Licensing.Models
@* @using Microsoft.AspNetCore.Identity; *@
@* @using Microsoft.AspNetCore.Authorization *@
@* @attribute [Authorize] *@
@* @inject IDbContextFactory<Licensing.Models.LicensingContext> DbFactory *@
@inject NavigationManager NavigationManager
<RadzenContent Container = "main">
<ChildContent>
<div class = "row">
<div class = "col-md-12">
<RadzenTemplateForm Data = "@Vendor" Visible = "@(Vendor != null)" TItem = "Licensing.Models.Vendors" Submit = "@FormSubmit">
<ChildContent>
<div style = "margin-bottom: 1rem" class = "row">
<div class = "col-md-3">
<RadzenLabel Text = "Name" Component = "Name" style = "width: 100%" />
</div>
<div class = "col-md-9">
<RadzenTextBox MaxLength = "256" style = "display:block; width: 100%" @bind-Value = "@(Vendor.Name)" Name = "Name" />
<RadzenRequiredValidator Component = "Name" Text = "Name is required" style = "position: absolute" />
</div>
</div>
<div style = "margin-bottom: 1rem" class = "row">
<div class = "col-md-3">
<RadzenLabel Text = "Email" Component = "Email" style = "width: 100%" />
</div>
<div class = "col-md-9">
<RadzenTextBox MaxLength = "256" style = "display: block; width: 100%" @bind-Value = "@(Vendor.Email)" Name = "Email" />
<RadzenRequiredValidator Component = "Email" Text = "Email is required" style = "position: absolute" />
</div>
</div>
<div style = "margin-bottom: 1rem" class = "row">
<div class = "col-md-3">
<RadzenLabel Text = "Last Name" Component = "LastName" style = "width: 100%">
</RadzenLabel>
</div>
<div class = "col-md-9">
<RadzenTextBox>
@* MaxLength = "256" style = "width: 100%" @bind-Value = "@(Vendor.LastName)" Name = "LastName"> *@
</RadzenTextBox>
</div>
</div>
<div style = "margin-bottom: 1rem" class = "row">
<div class = "col-md-3">
<RadzenLabel Text = "First Name" Component = "FirstName" style = "width: 100%">
</RadzenLabel>
</div>
<div class = "col-md-9">
<RadzenTextBox>
@* MaxLength = "256" style = "width: 100%" @bind-Value = "@(Vendor.FirstName)" Name = "FirstName"> *@
</RadzenTextBox>
</div>
</div>
<div style = "margin-bottom: 1rem" class = "row">
<div class = "col-md-3">
<RadzenLabel Text = "Phone" Component = "Phone" style = "width: 100%">
</RadzenLabel>
</div>
<div class = "col-md-9">
<RadzenTextBox>
@* MaxLength = "256" style = "width: 100%" @bind-Value = "@(Vendor.Phone)" Name = "Phone"> *@
</RadzenTextBox>
</div>
</div>
<div class = "row">
<div class = "col offset-sm-3">
<RadzenButton ButtonType = "ButtonType.Submit" Icon = "save" Text = "Save" ButtonStyle = "ButtonStyle.Primary">
</RadzenButton>
<RadzenButton ButtonStyle = "ButtonStyle.Light" style = "margin-left: 1rem" Text = "Cancel" Click = "@ButtonCancelClick">
</RadzenButton>
</div>
</div>
</ChildContent>
</RadzenTemplateForm>
</div>
</div>
</ChildContent>
</RadzenContent>
@code {
[Parameter(CaptureUnmatchedValues = true)]
public IReadOnlyDictionary<string, dynamic>? Attributes { get; set; }
[Inject]
protected NotificationService NotificationService { get; set; } = default!;
[Inject]
protected DialogService DialogService { get; set; } = default!;
protected Licensing.Models.Vendors? Vendor { get; set; }
protected virtual async System.Threading.Tasks.Task FormSubmit(Licensing.Models.Vendors args) { }
protected async System.Threading.Tasks.Task ButtonCancelClick(MouseEventArgs args)
{
await Task.Run(() => DialogService.Close(null));
}
}
EditVendor.razor (подкласс)
@*
DCE Aug 24
This is a dervied class from CreateEdit component class.
CreateEdit is reused such that entities can be created or edited.
Each subclass will perform any validation needed.
be sure to use base.BuildRenderTree as this is only called for the parent class.
*@
@page "/vendors/edit"
@using Microsoft.EntityFrameworkCore
@inherits VendorDetails
<PageTitle>Edit</PageTitle>
@{
base.BuildRenderTree(__builder);
}
@code {
[Parameter] public int Id { get; set; }
[Inject]
public LicensingContext? Context { get; set; }
protected override async System.Threading.Tasks.Task OnInitializedAsync()
{
await base.OnInitializedAsync();
base.Vendor = Context!.Vendors.FirstOrDefault(x => x.pkId == Id);
}
protected override async System.Threading.Tasks.Task FormSubmit(Licensing.Models.Vendors args)
{
if (base.Vendor != null)
{
try
{
await InvokeAsync(() => Context!.SaveChangesAsync());
DialogService.Close();
}
catch (System.Exception e)
{
NotificationService.Notify(
new NotificationMessage()
{
Severity = NotificationSeverity.Error,
Summary = $"Error: Unable to save Vendor!",
Detail = string.Format("Msg:{0}", e.Message.ToString())
});
}
}
}
}
Пытался использовать @inject IDBFactory... в компоненте razor, но это не дало мне доступа к теневым свойствам, поэтому я создал поле класса Context
, которое содержит экземпляр моего класса Apps DbContext, LicensingContext
РЕДАКТИРОВАТЬ 1 LicensingContext регистрируется как служба (для dbContext) в файле Program.cs.
Мне было интересно, вызовет ли внедрение моего класса LicensingContext для получения доступа Intellisense к теневым свойствам DbSets болезненные проблемы или это будет неэффективно? и почему.
Обычно это не вызывает серьезных проблем или неэффективности. Однако если LicensingContext
внедряется с помощью внедрения зависимостей (DI) и часто используется, это может привести к проблемам с производительностью. Поэтому важно убедиться, что область действия объекта контекста правильно настроена в управлении жизненным циклом.
Настройка DbContext как ограниченной области — рекомендуемый подход для балансировки производительности и использования ресурсов:
LicensingContext регистрируется как служба (для dbContext) в файле Program.cs.
Потому что вы зарегистрировали DbContext, используя код типа builder.Services.AddDbContext<YourDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
По умолчанию метод AddDbContext настраивает DbContext как ограниченный. Это означает, что для каждого запроса или операции создается новый экземпляр DbContext, но в рамках того же запроса экземпляр DbContext является общим.
это не дало мне доступа к теневым свойствам
Кстати, похоже, вы не настроили теневые свойства сущности в своем методе OnModelCreating.
Вы можете настроить свойства тени, используя Property<TProperty>(String)
.
// for example:
modelBuilder.Entity<Blog>()
.Property<DateTime>("LastUpdated");
Вы можете получить доступ к теневым свойствам через API ChangeTracker:
// for example:
context.Entry(myBlog).Property("LastUpdated").CurrentValue = DateTime.Now;
Вы можете обратиться к этой официальной документации за инструкциями.
большое спасибо. все решено.