从模型外键绑定值
Bind value from model foreign key
我想显示 Product.Category.Name 是子组件,但出现错误。
但是在父组件中 Product.Category.Name 为什么在子组件中不起作用?
我的模型:
public class Product
{
/// <summary>
/// Gets or sets the id.
/// </summary>
[Key]
[BindNever]
public int Id { get; set; }
/// <summary>
/// Gets or sets the name.
/// </summary>
[Required]
public string Name { get; set; }
/// <summary>
/// Gets or sets the price.
/// </summary>
[Required]
[Range(0, 500)]
public double Price { get; set; }
/// <summary>
/// Gets or sets the image.
/// </summary>
public byte[] Image { get; set; }
/// <summary>
/// Gets or sets the shade color.
/// </summary>
public string ShadeColor { get; set; }
/// <summary>
/// Gets or sets the category id.
/// </summary>
public int CategoryId { get; set; }
/// <summary>
/// Gets or sets the category.
/// </summary>
[ForeignKey("CategoryId")]
public virtual Category Category { get; set; }
}
我的父组件:
@page "/products"
@using BlazingShop.Data
@using BlazingShop.Services
@using BlazingShop.Pages.Components
@inject IProductService ProductService
<div class="d-flex">
<div>
<h1>Product List</h1>
</div>
<div class="ml-auto">
<BSButton Color="Color.Info" @onclick="LoadProductDetailsModal"><i class="fal fa-plus-circle mr-1"></i>Add New Product</BSButton>
</div>
</div>
<BSTable Class="w-75 m-auto">
<thead>
<tr>
<th>Name</th>
<th>Price</th>
<th>Shade Color</th>
<th>Category</th>
<th class="text-right">Action</th>
</tr>
</thead>
<tbody>
<SpinLoader IsLoading="isLoading" IsFaulted="isFaulted">
<LoadingTemplate>
<tr>
<td colspan="7">
<Circle Color="#e67e22" Size="60px" Center="true"></Circle>
</td>
</tr>
</LoadingTemplate>
<ContentTemplate>
@foreach (var product in products)
{
<tr>
<td>@product.Name</td>
<td>@product.Price</td>
<td>@product.ShadeColor</td>
<td>@product.Category.Name</td>
<td class="text-right">
<BSButton Color="Color.Primary" OnClick="(()=>LoadProductDetailsModalForEdit(product))"><i class="fal fa-edit mr-1"></i>Edit</BSButton>
<BSButton Color="Color.Danger" OnClick="(()=>LoadConfirmationModalForDelete(product))"><i class="fal fa-trash-alt mr-1"></i>Delete</BSButton>
</td>
</tr>
}
</ContentTemplate>
<FaultedContentTemplate>
<tr>
<td colspan="7">
<BSAlert Color="Color.Danger">
<span>An Exception occured - So no Products could be shown at this time</span>
</BSAlert>
</td>
</tr>
</FaultedContentTemplate>
</SpinLoader>
</tbody>
</BSTable>
<ProductDetails ProductDetailModalTitle="@productDetailModalTitle" @ref="ProductDetails" Product="product" OnSave="@RefreshProductList"></ProductDetails>
<ConfirmDelete Delete="@DeleteProduct" @ref="ConfirmDeleteModal"></ConfirmDelete>
@code {
private ProductDetails ProductDetails { get; set; }
Product product = new Product();
private List<Product> products;
private ConfirmDelete ConfirmDeleteModal { get; set; }
private List<Category> categories;
string productDetailModalTitle = string.Empty;
bool isFaulted = false;
bool isLoading = true;
int delay = 2000;
protected override async Task OnInitializedAsync()
{
await LoadProductList();
}
private async Task LoadProductList()
{
await TryLoadingProductListAsync (onSuccess: SuccessPath, onFaulted: FaultedPath);
}
void SuccessPath(List<Product> data)
{
products = data;
}
void FaultedPath(Exception e)
{
// log message, don't share it with the user
var fakeLog = e.Message;
}
async Task TryLoadingProductListAsync(Action<List<Product>> onSuccess, Action<Exception> onFaulted)
{
isLoading = true;
await Task.Delay(delay);
try
{
var data = await ProductService.GetProductsAsync();
isFaulted = false;
onSuccess(data);
}
catch (Exception e)
{
isFaulted = true;
onFaulted(e);
}
finally
{
isLoading = false;
}
}
private void LoadProductDetailsModal()
{
this.product = new Product();
categories = ProductService.GetCategoriesAsync();
this.product.CategoryId = categories[0].Id;
this.productDetailModalTitle = "Add New Product";
ProductDetails.Toggle();
}
private void LoadProductDetailsModalForEdit(Product product)
{
this.product = product;
categories = ProductService.GetCategoriesAsync();
this.productDetailModalTitle = product.Name;
ProductDetails.Toggle();
}
private void LoadConfirmationModalForDelete(Product product)
{
this.product = product;
ConfirmDeleteModal.Toggle();
}
private async Task DeleteProduct()
{
await ProductService.DeleteProductAsync(this.product);
await RefreshProductList();
ConfirmDeleteModal.Toggle();
}
private async Task<List<Product>> RefreshProductList()
{
products = await ProductService.GetProductsAsync();
product = new Product();
return products;
}
}
我的子组件:
@using BlazingShop.Services
@using BlazingShop.Data
@using BlazorInputFile
@using System.IO
@inject IProductService ProductService
<BSModal @ref="@ProductDetailsModal" IsCentered="true">
<BSModalHeader OnClick="@OnToggle">@ProductDetailModalTitle</BSModalHeader>
<EditForm Model="Product" OnValidSubmit="HandleValidSubmit">
<BSModalBody style="min-height: 150px;">
<BSFormGroup Class="row">
<div class="d-flex">
<label For="ProductName" class="col-4 m-0 align-self-center">Name:</label>
<div class="col-7">
<BSInput Id="ProductName" InputType="InputType.Text" @bind-Value="Product.Name"></BSInput>
<ValidationMessage For="@(() => Product.Name)"></ValidationMessage>
</div>
</div>
<div class="d-flex">
<label For="ProductCategory" class="col-4 m-0 align-self-center">Category:</label>
<div class="col-7">
<BSInput Id="ProductCategory" InputType="InputType.Text" @bind-Value="Product.Category.Name"></BSInput>
<ValidationMessage For="@(() => Product.Category.Name)"></ValidationMessage>
</div>
</div>
<div class="d-flex">
<label For="ProductPrice" class="col-4 m-0 align-self-center">Price:</label>
<div class="col-7">
<BSInput Id="ProductPrice" InputType="InputType.Text" @bind-Value="Product.Price"></BSInput>
<ValidationMessage For="@(() => Product.Price)"></ValidationMessage>
</div>
</div>
<div class="d-flex">
<label For="ProductShadeColor" class="col-4 m-0 align-self-center">Shade Color:</label>
<div class="col-7">
<BSInput Id="ProductShadeColor" InputType="InputType.Text" @bind-Value="Product.ShadeColor"></BSInput>
<ValidationMessage For="@(() => Product.ShadeColor)"></ValidationMessage>
</div>
</div>
<div class="d-flex">
<label For="ProductImage" class="col-4 m-0 align-self-center">Upload Image:</label>
<div class="col-7">
<BSBasicInput InputType="InputType.File" Id="ProductImage" Value="string.Empty" OnChange=""></BSBasicInput>
<ValidationMessage For="@(() => Product.Image)"></ValidationMessage>
</div>
</div>
</BSFormGroup>
</BSModalBody>
<BSModalFooter>
<DataAnnotationsValidator />
<BSButton Color="Color.Primary" ButtonType="ButtonType.Submit">Save Changes</BSButton>
<BSButton Color="Color.Secondary" @onclick="@OnToggle">Close</BSButton>
</BSModalFooter>
</EditForm>
</BSModal>
@code {
BSModal ProductDetailsModal;
[Parameter]
public Product Product { get; set; }
[Parameter]
public string ProductDetailModalTitle { get; set; }
[Parameter]
public EventCallback<bool> OnSave { get; set; }
public byte[] ImageUploaded { get; set; }
void OnToggle(MouseEventArgs e)
{
Toggle();
}
public void Toggle()
{
ProductDetailsModal.Toggle();
}
private async void HandleValidSubmit()
{
Toggle();
if (Product.Id == 0)
{
await ProductService.AddProductAsync(Product);
}
else
{
await ProductService.EditProductAsync(Product);
}
await OnSave.InvokeAsync(true);
}
async Task HandleSelection(IFileListEntry[] files)
{
var file = files.FirstOrDefault();
if (file != null)
{
var ms = new MemoryStream();
await file.Data.CopyToAsync(ms);
ImageUploaded = ms.ToArray();
}
}
string ConvertImageToDisplay(byte[] image)
{
if (image != null)
{
var base64 = Convert.ToBase64String(image);
var finalStr = $"data:image/jpg;base64,{base64}";
return finalStr;
}
else
{
return string.Empty;
}
}
}
你能帮我在子组件中显示 Product.Category.Name(或 id)吗,谢谢。
嘿,我刚找到答案:
在子组件中需要做一个 select :
<BSInput Id="ProductCategory" InputType="InputType.Select" @bind-Value="Product.CategoryId">
@foreach (var category in Categories)
{
<option value="@category.Id">@category.Name</option>
}
</BSInput>
我需要加载组件列表当我加载组件时:
@{
public List<Category> Categories { get; set; }
protected override async Task OnInitializedAsync()
{
Categories = ProductService.GetCategoriesAsync();
}
}
我想显示 Product.Category.Name 是子组件,但出现错误。 但是在父组件中 Product.Category.Name 为什么在子组件中不起作用?
我的模型:
public class Product
{
/// <summary>
/// Gets or sets the id.
/// </summary>
[Key]
[BindNever]
public int Id { get; set; }
/// <summary>
/// Gets or sets the name.
/// </summary>
[Required]
public string Name { get; set; }
/// <summary>
/// Gets or sets the price.
/// </summary>
[Required]
[Range(0, 500)]
public double Price { get; set; }
/// <summary>
/// Gets or sets the image.
/// </summary>
public byte[] Image { get; set; }
/// <summary>
/// Gets or sets the shade color.
/// </summary>
public string ShadeColor { get; set; }
/// <summary>
/// Gets or sets the category id.
/// </summary>
public int CategoryId { get; set; }
/// <summary>
/// Gets or sets the category.
/// </summary>
[ForeignKey("CategoryId")]
public virtual Category Category { get; set; }
}
我的父组件:
@page "/products"
@using BlazingShop.Data
@using BlazingShop.Services
@using BlazingShop.Pages.Components
@inject IProductService ProductService
<div class="d-flex">
<div>
<h1>Product List</h1>
</div>
<div class="ml-auto">
<BSButton Color="Color.Info" @onclick="LoadProductDetailsModal"><i class="fal fa-plus-circle mr-1"></i>Add New Product</BSButton>
</div>
</div>
<BSTable Class="w-75 m-auto">
<thead>
<tr>
<th>Name</th>
<th>Price</th>
<th>Shade Color</th>
<th>Category</th>
<th class="text-right">Action</th>
</tr>
</thead>
<tbody>
<SpinLoader IsLoading="isLoading" IsFaulted="isFaulted">
<LoadingTemplate>
<tr>
<td colspan="7">
<Circle Color="#e67e22" Size="60px" Center="true"></Circle>
</td>
</tr>
</LoadingTemplate>
<ContentTemplate>
@foreach (var product in products)
{
<tr>
<td>@product.Name</td>
<td>@product.Price</td>
<td>@product.ShadeColor</td>
<td>@product.Category.Name</td>
<td class="text-right">
<BSButton Color="Color.Primary" OnClick="(()=>LoadProductDetailsModalForEdit(product))"><i class="fal fa-edit mr-1"></i>Edit</BSButton>
<BSButton Color="Color.Danger" OnClick="(()=>LoadConfirmationModalForDelete(product))"><i class="fal fa-trash-alt mr-1"></i>Delete</BSButton>
</td>
</tr>
}
</ContentTemplate>
<FaultedContentTemplate>
<tr>
<td colspan="7">
<BSAlert Color="Color.Danger">
<span>An Exception occured - So no Products could be shown at this time</span>
</BSAlert>
</td>
</tr>
</FaultedContentTemplate>
</SpinLoader>
</tbody>
</BSTable>
<ProductDetails ProductDetailModalTitle="@productDetailModalTitle" @ref="ProductDetails" Product="product" OnSave="@RefreshProductList"></ProductDetails>
<ConfirmDelete Delete="@DeleteProduct" @ref="ConfirmDeleteModal"></ConfirmDelete>
@code {
private ProductDetails ProductDetails { get; set; }
Product product = new Product();
private List<Product> products;
private ConfirmDelete ConfirmDeleteModal { get; set; }
private List<Category> categories;
string productDetailModalTitle = string.Empty;
bool isFaulted = false;
bool isLoading = true;
int delay = 2000;
protected override async Task OnInitializedAsync()
{
await LoadProductList();
}
private async Task LoadProductList()
{
await TryLoadingProductListAsync (onSuccess: SuccessPath, onFaulted: FaultedPath);
}
void SuccessPath(List<Product> data)
{
products = data;
}
void FaultedPath(Exception e)
{
// log message, don't share it with the user
var fakeLog = e.Message;
}
async Task TryLoadingProductListAsync(Action<List<Product>> onSuccess, Action<Exception> onFaulted)
{
isLoading = true;
await Task.Delay(delay);
try
{
var data = await ProductService.GetProductsAsync();
isFaulted = false;
onSuccess(data);
}
catch (Exception e)
{
isFaulted = true;
onFaulted(e);
}
finally
{
isLoading = false;
}
}
private void LoadProductDetailsModal()
{
this.product = new Product();
categories = ProductService.GetCategoriesAsync();
this.product.CategoryId = categories[0].Id;
this.productDetailModalTitle = "Add New Product";
ProductDetails.Toggle();
}
private void LoadProductDetailsModalForEdit(Product product)
{
this.product = product;
categories = ProductService.GetCategoriesAsync();
this.productDetailModalTitle = product.Name;
ProductDetails.Toggle();
}
private void LoadConfirmationModalForDelete(Product product)
{
this.product = product;
ConfirmDeleteModal.Toggle();
}
private async Task DeleteProduct()
{
await ProductService.DeleteProductAsync(this.product);
await RefreshProductList();
ConfirmDeleteModal.Toggle();
}
private async Task<List<Product>> RefreshProductList()
{
products = await ProductService.GetProductsAsync();
product = new Product();
return products;
}
}
我的子组件:
@using BlazingShop.Services
@using BlazingShop.Data
@using BlazorInputFile
@using System.IO
@inject IProductService ProductService
<BSModal @ref="@ProductDetailsModal" IsCentered="true">
<BSModalHeader OnClick="@OnToggle">@ProductDetailModalTitle</BSModalHeader>
<EditForm Model="Product" OnValidSubmit="HandleValidSubmit">
<BSModalBody style="min-height: 150px;">
<BSFormGroup Class="row">
<div class="d-flex">
<label For="ProductName" class="col-4 m-0 align-self-center">Name:</label>
<div class="col-7">
<BSInput Id="ProductName" InputType="InputType.Text" @bind-Value="Product.Name"></BSInput>
<ValidationMessage For="@(() => Product.Name)"></ValidationMessage>
</div>
</div>
<div class="d-flex">
<label For="ProductCategory" class="col-4 m-0 align-self-center">Category:</label>
<div class="col-7">
<BSInput Id="ProductCategory" InputType="InputType.Text" @bind-Value="Product.Category.Name"></BSInput>
<ValidationMessage For="@(() => Product.Category.Name)"></ValidationMessage>
</div>
</div>
<div class="d-flex">
<label For="ProductPrice" class="col-4 m-0 align-self-center">Price:</label>
<div class="col-7">
<BSInput Id="ProductPrice" InputType="InputType.Text" @bind-Value="Product.Price"></BSInput>
<ValidationMessage For="@(() => Product.Price)"></ValidationMessage>
</div>
</div>
<div class="d-flex">
<label For="ProductShadeColor" class="col-4 m-0 align-self-center">Shade Color:</label>
<div class="col-7">
<BSInput Id="ProductShadeColor" InputType="InputType.Text" @bind-Value="Product.ShadeColor"></BSInput>
<ValidationMessage For="@(() => Product.ShadeColor)"></ValidationMessage>
</div>
</div>
<div class="d-flex">
<label For="ProductImage" class="col-4 m-0 align-self-center">Upload Image:</label>
<div class="col-7">
<BSBasicInput InputType="InputType.File" Id="ProductImage" Value="string.Empty" OnChange=""></BSBasicInput>
<ValidationMessage For="@(() => Product.Image)"></ValidationMessage>
</div>
</div>
</BSFormGroup>
</BSModalBody>
<BSModalFooter>
<DataAnnotationsValidator />
<BSButton Color="Color.Primary" ButtonType="ButtonType.Submit">Save Changes</BSButton>
<BSButton Color="Color.Secondary" @onclick="@OnToggle">Close</BSButton>
</BSModalFooter>
</EditForm>
</BSModal>
@code {
BSModal ProductDetailsModal;
[Parameter]
public Product Product { get; set; }
[Parameter]
public string ProductDetailModalTitle { get; set; }
[Parameter]
public EventCallback<bool> OnSave { get; set; }
public byte[] ImageUploaded { get; set; }
void OnToggle(MouseEventArgs e)
{
Toggle();
}
public void Toggle()
{
ProductDetailsModal.Toggle();
}
private async void HandleValidSubmit()
{
Toggle();
if (Product.Id == 0)
{
await ProductService.AddProductAsync(Product);
}
else
{
await ProductService.EditProductAsync(Product);
}
await OnSave.InvokeAsync(true);
}
async Task HandleSelection(IFileListEntry[] files)
{
var file = files.FirstOrDefault();
if (file != null)
{
var ms = new MemoryStream();
await file.Data.CopyToAsync(ms);
ImageUploaded = ms.ToArray();
}
}
string ConvertImageToDisplay(byte[] image)
{
if (image != null)
{
var base64 = Convert.ToBase64String(image);
var finalStr = $"data:image/jpg;base64,{base64}";
return finalStr;
}
else
{
return string.Empty;
}
}
}
你能帮我在子组件中显示 Product.Category.Name(或 id)吗,谢谢。
嘿,我刚找到答案: 在子组件中需要做一个 select :
<BSInput Id="ProductCategory" InputType="InputType.Select" @bind-Value="Product.CategoryId">
@foreach (var category in Categories)
{
<option value="@category.Id">@category.Name</option>
}
</BSInput>
我需要加载组件列表当我加载组件时:
@{
public List<Category> Categories { get; set; }
protected override async Task OnInitializedAsync()
{
Categories = ProductService.GetCategoriesAsync();
}
}