Implemented selector properties for admin pages
This commit is contained in:
@@ -17,9 +17,12 @@ public interface IAdminPropertyGenerator<TProperty> {
|
|||||||
IAdminPropertyGenerator<TProperty> Description(string description);
|
IAdminPropertyGenerator<TProperty> Description(string description);
|
||||||
IAdminPropertyGenerator<TProperty> Prefix(string prefix);
|
IAdminPropertyGenerator<TProperty> Prefix(string prefix);
|
||||||
IAdminPropertyGenerator<TProperty> Validator(Func<TProperty, string> validator);
|
IAdminPropertyGenerator<TProperty> Validator(Func<TProperty, string> validator);
|
||||||
IAdminPropertyGenerator<TProperty> IsSelector<TSelector>();
|
IAdminPropertyGenerator<TProperty> IsSelector(bool selector = true);
|
||||||
|
IAdminPropertyGenerator<TProperty> IsSelector<TSelectorType>(bool selector = true);
|
||||||
IAdminPropertyGenerator<TProperty> Parser<TModel>(Func<TModel, string, TProperty> parser);
|
IAdminPropertyGenerator<TProperty> Parser<TModel>(Func<TModel, string, TProperty> parser);
|
||||||
|
IAdminPropertyGenerator<TProperty> Parser<TModel, TInput>(Func<TModel, TInput, TProperty> parser);
|
||||||
IAdminPropertyGenerator<TProperty> ParserForListType<TModel, TInnerProperty>(Func<TModel, string, TInnerProperty> parser);
|
IAdminPropertyGenerator<TProperty> ParserForListType<TModel, TInnerProperty>(Func<TModel, string, TInnerProperty> parser);
|
||||||
|
IAdminPropertyGenerator<TProperty> ParserForListType<TModel, TInnerProperty, TInput>(Func<TModel, TInput, TInnerProperty> parser);
|
||||||
IAdminPropertyGenerator<TProperty> DisplayProperty<TListingProperty>(Expression<Func<TProperty, TListingProperty>> propertyExpression);
|
IAdminPropertyGenerator<TProperty> DisplayProperty<TListingProperty>(Expression<Func<TProperty, TListingProperty>> propertyExpression);
|
||||||
IAdminPropertyGenerator<TProperty> DisplayPropertyForListType<TInnerProperty>(Expression<Func<TInnerProperty, object>> propertyExpression);
|
IAdminPropertyGenerator<TProperty> DisplayPropertyForListType<TInnerProperty>(Expression<Func<TInnerProperty, object>> propertyExpression);
|
||||||
|
|
||||||
|
|||||||
@@ -76,18 +76,34 @@ internal sealed class AdminPropertyGenerator<TProperty>(string name, Type type)
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IAdminPropertyGenerator<TProperty> IsSelector<TSelector>() {
|
public IAdminPropertyGenerator<TProperty> IsSelector(bool selector = true) {
|
||||||
_property.SelectorType = typeof(TSelector);
|
_property.Selector = selector;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IAdminPropertyGenerator<TProperty> IsSelector<TSelectorType>(bool selector = true) {
|
||||||
|
_property.Selector = true;
|
||||||
|
_property.SelectorType = typeof(TSelectorType);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IAdminPropertyGenerator<TProperty> Parser<TModel>(Func<TModel, string, TProperty> parser) {
|
public IAdminPropertyGenerator<TProperty> Parser<TModel>(Func<TModel, string, TProperty> parser) {
|
||||||
_property.Parser = (o, s) => parser.Invoke((TModel)o, s);
|
_property.Parser = (o, s) => parser.Invoke((TModel)o, s.ToString());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IAdminPropertyGenerator<TProperty> Parser<TModel, TInput>(Func<TModel, TInput, TProperty> parser) {
|
||||||
|
_property.Parser = (o, s) => parser.Invoke((TModel)o, (TInput)s);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IAdminPropertyGenerator<TProperty> ParserForListType<TModel, TInnerProperty>(Func<TModel, string, TInnerProperty> parser) {
|
public IAdminPropertyGenerator<TProperty> ParserForListType<TModel, TInnerProperty>(Func<TModel, string, TInnerProperty> parser) {
|
||||||
_property.Parser = (o, s) => parser.Invoke((TModel)o, s);
|
_property.Parser = (o, s) => parser.Invoke((TModel)o, s.ToString());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IAdminPropertyGenerator<TProperty> ParserForListType<TModel, TInnerProperty, TInput>(Func<TModel, TInput, TInnerProperty> parser) {
|
||||||
|
_property.Parser = (o, s) => parser.Invoke((TModel)o, (TInput)s);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,14 +18,14 @@ public sealed class AdminPageProperty {
|
|||||||
public bool Required { get; set; }
|
public bool Required { get; set; }
|
||||||
public bool Ignore { get; set; }
|
public bool Ignore { get; set; }
|
||||||
public bool Unique { get; set; }
|
public bool Unique { get; set; }
|
||||||
|
public bool Selector { get; set; }
|
||||||
|
public Type SelectorType { get; set; }
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public Type Type { get; set; }
|
public Type Type { get; set; }
|
||||||
|
|
||||||
public Type SelectorType { get; set; }
|
|
||||||
|
|
||||||
public Func<object, string> Validator { get; set; }
|
public Func<object, string> Validator { get; set; }
|
||||||
public Func<object, string, object> Parser { get; set; }
|
public Func<object, object, object> Parser { get; set; }
|
||||||
|
|
||||||
public object GetValue(object entry) {
|
public object GetValue(object entry) {
|
||||||
return entry.GetType().GetProperty(Name)?.GetValue(entry);
|
return entry.GetType().GetProperty(Name)?.GetValue(entry);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@rendermode InteractiveServer
|
@rendermode InteractiveServer
|
||||||
|
|
||||||
@using System.Collections
|
@using System.Collections
|
||||||
|
@using System.Globalization
|
||||||
@using BlazorStrap
|
@using BlazorStrap
|
||||||
@using BlazorStrap.Shared.Components.Modal
|
@using BlazorStrap.Shared.Components.Modal
|
||||||
@using static Microsoft.AspNetCore.Components.Web.RenderMode
|
@using static Microsoft.AspNetCore.Components.Web.RenderMode
|
||||||
@@ -46,23 +47,23 @@
|
|||||||
</BSListGroupItem>
|
</BSListGroupItem>
|
||||||
<BSListGroupItem>
|
<BSListGroupItem>
|
||||||
<div>
|
<div>
|
||||||
@if (prop.SelectorType is null) {
|
@if (!prop.Selector) {
|
||||||
<form style="display: flex; gap: 20px" @onsubmit="() => AddListItem(prop)">
|
<form style="display: flex; gap: 20px" @onsubmit="() => AddListItem(prop)">
|
||||||
<input type="text" class="form-control" @onchange="v => _inputValues[prop] = (string)v.Value" required/>
|
<input type="text" class="form-control" @onchange="v => _inputValues[prop] = (string)v.Value" required/>
|
||||||
<BSButton Color="BSColor.Secondary" IsSubmit="true">Add</BSButton>
|
<BSButton Color="BSColor.Secondary" IsSubmit="true">Add</BSButton>
|
||||||
</form>
|
</form>
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@*<BSInput InputType="InputType.Select"> TODO: implement selector
|
<form style="display: flex; gap: 20px" @onsubmit="() => AddListItem(prop)">
|
||||||
<option selected>Select group</option>
|
<select class="form-select" @onchange="e => _inputValues[prop] = ReadSelectorValue(prop, e.Value)">
|
||||||
|
<option selected>Select</option>
|
||||||
|
|
||||||
@foreach (var group in _allGroups) {
|
@foreach (var element in SetupSelectorProperty(prop).GetAwaiter().GetResult()) {
|
||||||
@if (_group.Permissions.All(g => g.PermissionName != group.Name) && group.Name != _group.Name) {
|
<option value="@element.Item2">@element.Item1</option>
|
||||||
<option value="@group.Name">@group.Name.Replace("group.", "")</option>
|
|
||||||
}
|
}
|
||||||
}
|
</select>
|
||||||
</BSInput>
|
<BSButton Color="BSColor.Secondary" IsSubmit="true">Add</BSButton>
|
||||||
<BSButton Color="BSColor.Secondary">Add</BSButton>*@
|
</form>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</BSListGroupItem>
|
</BSListGroupItem>
|
||||||
@@ -80,6 +81,16 @@
|
|||||||
<input type="text" class="form-control" required="@IsRequired(prop)" disabled="@IsDisabled(prop)" value="@GetPropertyValue(prop)" @onchange="e => _values[prop] = prop.Prefix + e.Value"/>
|
<input type="text" class="form-control" required="@IsRequired(prop)" disabled="@IsDisabled(prop)" value="@GetPropertyValue(prop)" @onchange="e => _values[prop] = prop.Prefix + e.Value"/>
|
||||||
</BSInputGroup>
|
</BSInputGroup>
|
||||||
}
|
}
|
||||||
|
else if (prop.Selector) {
|
||||||
|
<BSLabel>@prop.DisplayName</BSLabel>
|
||||||
|
<select class="form-select" @onchange="e => _values[prop] = ReadSelectorValue(prop, e.Value)">
|
||||||
|
<option>Select</option>
|
||||||
|
|
||||||
|
@foreach (var element in SetupSelectorProperty(prop).GetAwaiter().GetResult()) {
|
||||||
|
<option value="@element.Item2" selected="@IsIndexSelected(prop, element.Item2)">@element.Item1</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
<BSLabel>@prop.DisplayName</BSLabel>
|
<BSLabel>@prop.DisplayName</BSLabel>
|
||||||
<input type="@GetInputType(prop)" class="form-control" required="@IsRequired(prop)" disabled="@IsDisabled(prop)" value="@GetPropertyValue(prop)" @onchange="e => _values[prop] = e.Value"/>
|
<input type="@GetInputType(prop)" class="form-control" required="@IsRequired(prop)" disabled="@IsDisabled(prop)" value="@GetPropertyValue(prop)" @onchange="e => _values[prop] = e.Value"/>
|
||||||
@@ -117,16 +128,18 @@
|
|||||||
private ValidationMessageStore _validation;
|
private ValidationMessageStore _validation;
|
||||||
private Dictionary<AdminPageProperty, FieldIdentifier> _validationIdentifiers;
|
private Dictionary<AdminPageProperty, FieldIdentifier> _validationIdentifiers;
|
||||||
private IDictionary<AdminPageProperty, object> _values;
|
private IDictionary<AdminPageProperty, object> _values;
|
||||||
|
private Dictionary<AdminPageProperty, object[]> _selectorValues;
|
||||||
private IModelRepository _repository;
|
private IModelRepository _repository;
|
||||||
|
|
||||||
private AdminPage _currentPage;
|
private AdminPage _currentPage;
|
||||||
private object _entry;
|
private object _entry;
|
||||||
private bool _isEdit;
|
private bool _isEdit;
|
||||||
private IDictionary<AdminPageProperty, string> _inputValues;
|
private IDictionary<AdminPageProperty, object> _inputValues;
|
||||||
|
|
||||||
public async Task Show(AdminPage page, object entryToEdit = null) {
|
public async Task Show(AdminPage page, object entryToEdit = null) {
|
||||||
_entry = null;
|
_entry = null;
|
||||||
_inputValues = new Dictionary<AdminPageProperty, string>();
|
_inputValues = new Dictionary<AdminPageProperty, object>();
|
||||||
|
_selectorValues = new Dictionary<AdminPageProperty, object[]>();
|
||||||
|
|
||||||
_currentPage = page;
|
_currentPage = page;
|
||||||
_entry = entryToEdit;
|
_entry = entryToEdit;
|
||||||
@@ -158,13 +171,14 @@
|
|||||||
private bool IsDisabled(AdminPageProperty prop) => (_isEdit && !prop.Editable) || prop.Generated;
|
private bool IsDisabled(AdminPageProperty prop) => (_isEdit && !prop.Editable) || prop.Generated;
|
||||||
private bool IsRequired(AdminPageProperty prop) => !_isEdit ? prop.Required : prop.Required && prop.EditDisplayValue;
|
private bool IsRequired(AdminPageProperty prop) => !_isEdit ? prop.Required : prop.Required && prop.EditDisplayValue;
|
||||||
private bool IsSwitch(AdminPageProperty prop) => prop.Type == typeof(bool);
|
private bool IsSwitch(AdminPageProperty prop) => prop.Type == typeof(bool);
|
||||||
|
private bool IsListType(AdminPageProperty prop) => IsListType(prop.Type);
|
||||||
|
|
||||||
private bool IsListType(AdminPageProperty prop) {
|
private bool IsListType(Type type) {
|
||||||
if (!prop.Type.IsGenericType) return false;
|
if (!type.IsGenericType) return false;
|
||||||
var generic = prop.Type.GenericTypeArguments[0];
|
var generic = type.GenericTypeArguments[0];
|
||||||
var gListType = typeof(IList<>).MakeGenericType(generic);
|
var gListType = typeof(IList<>).MakeGenericType(generic);
|
||||||
var iListType = typeof(List<>).MakeGenericType(generic);
|
var iListType = typeof(List<>).MakeGenericType(generic);
|
||||||
return prop.Type.IsAssignableFrom(gListType) || prop.Type.IsAssignableFrom(iListType);
|
return type.IsAssignableFrom(gListType) || type.IsAssignableFrom(iListType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IList<string> GetListPropertyValues(AdminPageProperty prop) {
|
private IList<string> GetListPropertyValues(AdminPageProperty prop) {
|
||||||
@@ -232,6 +246,7 @@
|
|||||||
_validation.Clear();
|
_validation.Clear();
|
||||||
foreach (var value in _values) {
|
foreach (var value in _values) {
|
||||||
if (value.Key.Unique) {
|
if (value.Key.Unique) {
|
||||||
|
if (value.Value == value.Key.GetValue(_entry)) continue;
|
||||||
var repo = Provider.GetService(_currentPage.RepositoryProvider) as IModelRepository;
|
var repo = Provider.GetService(_currentPage.RepositoryProvider) as IModelRepository;
|
||||||
var data = repo!.ReadAllO().GetAwaiter().GetResult();
|
var data = repo!.ReadAllO().GetAwaiter().GetResult();
|
||||||
foreach (var entry in data) {
|
foreach (var entry in data) {
|
||||||
@@ -255,7 +270,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void AddListItem(AdminPageProperty prop) {
|
private void AddListItem(AdminPageProperty prop) {
|
||||||
if (!_inputValues.TryGetValue(prop, out var input)) {
|
if (!_inputValues.TryGetValue(prop, out var input) || input is null) {
|
||||||
Alerts.FireAsync(new SweetAlertOptions {
|
Alerts.FireAsync(new SweetAlertOptions {
|
||||||
Title = "Error!",
|
Title = "Error!",
|
||||||
Text = "Please enter a value!",
|
Text = "Please enter a value!",
|
||||||
@@ -269,6 +284,43 @@
|
|||||||
list?.Add(value);
|
list?.Add(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<(string, int)[]> SetupSelectorProperty(AdminPageProperty property) {
|
||||||
|
var type = property.SelectorType ?? property.Type;
|
||||||
|
if (IsListType(type)) {
|
||||||
|
type = type.GenericTypeArguments[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
var page = PageProvider.HasPageFor(type);
|
||||||
|
if (page is null) {
|
||||||
|
throw new ArgumentException($"'{property.Name}' cannot be a selector because a admin page for '{type.Name}' does not exist!");
|
||||||
|
}
|
||||||
|
|
||||||
|
var repo = Provider.GetService(page.RepositoryProvider) as IModelRepository;
|
||||||
|
var objects = (await repo!.ReadAllO()).ToArray();
|
||||||
|
_selectorValues[property] = objects;
|
||||||
|
|
||||||
|
var data = new List<(string, int)>();
|
||||||
|
for (var i = 0; i < objects.Length; i++) {
|
||||||
|
data.Add((MapPropertyValue(objects[i], property), i));
|
||||||
|
}
|
||||||
|
|
||||||
|
return data.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsIndexSelected(AdminPageProperty property, int index) {
|
||||||
|
var value = property.GetValue(_entry);
|
||||||
|
if (value is null) return false;
|
||||||
|
return _selectorValues[property][index] == value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private object ReadSelectorValue(AdminPageProperty property, object value) {
|
||||||
|
if (!int.TryParse(value.ToString(), out int result)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _selectorValues[property][result];
|
||||||
|
}
|
||||||
|
|
||||||
private async void Save() {
|
private async void Save() {
|
||||||
if (_isEdit && _currentPage.Permissions.Update is not null) {
|
if (_isEdit && _currentPage.Permissions.Update is not null) {
|
||||||
if (!await Permissions.HasPermission(Auth.User, _currentPage.Permissions.Update)) {
|
if (!await Permissions.HasPermission(Auth.User, _currentPage.Permissions.Update)) {
|
||||||
@@ -292,7 +344,7 @@
|
|||||||
|
|
||||||
foreach (var value in _values) {
|
foreach (var value in _values) {
|
||||||
if (IsListType(value.Key)) continue;
|
if (IsListType(value.Key)) continue;
|
||||||
value.Key.SetValue(_entry, value.Key.Parser?.Invoke(_entry, (string)value.Value) ?? value.Value);
|
value.Key.SetValue(_entry, value.Key.Parser?.Invoke(_entry, value.Value) ?? Convert.ChangeType(value.Value, value.Key.Type));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_isEdit) {
|
if (!_isEdit) {
|
||||||
|
|||||||
@@ -63,7 +63,8 @@ public class HopAdminContext : AdminPagesContext {
|
|||||||
.ViewPermission(AdminPermissions.ViewGroups)
|
.ViewPermission(AdminPermissions.ViewGroups)
|
||||||
.CreatePermission(AdminPermissions.AddGroup)
|
.CreatePermission(AdminPermissions.AddGroup)
|
||||||
.UpdatePermission(AdminPermissions.EditGroup)
|
.UpdatePermission(AdminPermissions.EditGroup)
|
||||||
.DeletePermission(AdminPermissions.DeleteGroup);
|
.DeletePermission(AdminPermissions.DeleteGroup)
|
||||||
|
.ListingProperty(g => g.Name);
|
||||||
|
|
||||||
generator.Page<PermissionGroup>().Property(g => g.Name)
|
generator.Page<PermissionGroup>().Property(g => g.Name)
|
||||||
.Prefix("group.");
|
.Prefix("group.");
|
||||||
|
|||||||
@@ -134,8 +134,8 @@
|
|||||||
throw new ArgumentException($"AdminPage '{_pageData.Title}' does not specify a model repository!'");
|
throw new ArgumentException($"AdminPage '{_pageData.Title}' does not specify a model repository!'");
|
||||||
_modelRepository = Provider.GetService(_pageData.RepositoryProvider) as IModelRepository;
|
_modelRepository = Provider.GetService(_pageData.RepositoryProvider) as IModelRepository;
|
||||||
|
|
||||||
_hasEditPermission = await Permissions.HasPermission(Auth.User, _pageData.Permissions.Update);
|
_hasEditPermission = _pageData.Permissions.Update is null || await Permissions.HasPermission(Auth.User, _pageData.Permissions.Update);
|
||||||
_hasDeletePermission = await Permissions.HasPermission(Auth.User, _pageData.Permissions.Delete);
|
_hasDeletePermission = _pageData.Permissions.Delete is null || await Permissions.HasPermission(Auth.User, _pageData.Permissions.Delete);
|
||||||
|
|
||||||
await Reload();
|
await Reload();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
using FrontendTest.Providers;
|
||||||
using HopFrame.Web.Admin;
|
using HopFrame.Web.Admin;
|
||||||
|
using HopFrame.Web.Admin.Generators;
|
||||||
using HopFrame.Web.Admin.Models;
|
using HopFrame.Web.Admin.Models;
|
||||||
using RestApiTest.Models;
|
using RestApiTest.Models;
|
||||||
|
|
||||||
@@ -8,5 +10,29 @@ public class AdminContext : AdminPagesContext {
|
|||||||
|
|
||||||
public AdminPage<Address> Addresses { get; set; }
|
public AdminPage<Address> Addresses { get; set; }
|
||||||
public AdminPage<Employee> Employees { get; set; }
|
public AdminPage<Employee> Employees { get; set; }
|
||||||
|
|
||||||
|
public override void OnModelCreating(IAdminContextGenerator generator) {
|
||||||
|
base.OnModelCreating(generator);
|
||||||
|
|
||||||
|
generator.Page<Employee>()
|
||||||
|
.Property(e => e.Address)
|
||||||
|
.IsSelector();
|
||||||
|
|
||||||
|
generator.Page<Address>()
|
||||||
|
.Property(a => a.Employee)
|
||||||
|
.Ignore();
|
||||||
|
|
||||||
|
generator.Page<Address>()
|
||||||
|
.Property(a => a.AddressId)
|
||||||
|
.IsSelector<Employee>()
|
||||||
|
.Parser<Address, Employee>((model, e) => model.AddressId = e.EmployeeId);
|
||||||
|
|
||||||
|
generator.Page<Employee>()
|
||||||
|
.ConfigureRepository<EmployeeProvider>()
|
||||||
|
.ListingProperty(e => e.Name);
|
||||||
|
|
||||||
|
generator.Page<Address>()
|
||||||
|
.ConfigureRepository<AddressProvider>()
|
||||||
|
.ListingProperty(a => a.City);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,24 @@
|
|||||||
using HopFrame.Database;
|
using HopFrame.Database;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using RestApiTest.Models;
|
||||||
|
|
||||||
namespace FrontendTest;
|
namespace FrontendTest;
|
||||||
|
|
||||||
public class DatabaseContext : HopDbContextBase {
|
public class DatabaseContext : HopDbContextBase {
|
||||||
|
public DbSet<Employee> Employees { get; set; }
|
||||||
|
public DbSet<Address> Addresses { get; set; }
|
||||||
|
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
|
||||||
base.OnConfiguring(optionsBuilder);
|
base.OnConfiguring(optionsBuilder);
|
||||||
|
|
||||||
optionsBuilder.UseSqlite(@"Data Source=C:\Users\leon\Documents\Projekte\HopFrame\test\RestApiTest\bin\Debug\net8.0\test.db;Mode=ReadWrite;");
|
optionsBuilder.UseSqlite(@"Data Source=C:\Users\leon\Documents\Projekte\HopFrame\test\RestApiTest\bin\Debug\net8.0\test.db;Mode=ReadWrite;");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnModelCreating(ModelBuilder modelBuilder) {
|
||||||
|
base.OnModelCreating(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity<Employee>()
|
||||||
|
.HasOne(e => e.Address)
|
||||||
|
.WithOne(a => a.Employee);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
29
test/FrontendTest/Providers/AddressProvider.cs
Normal file
29
test/FrontendTest/Providers/AddressProvider.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using HopFrame.Web.Admin;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using RestApiTest.Models;
|
||||||
|
|
||||||
|
namespace FrontendTest.Providers;
|
||||||
|
|
||||||
|
public class AddressProvider(DatabaseContext context) : ModelRepository<Address> {
|
||||||
|
|
||||||
|
public override async Task<IEnumerable<Address>> ReadAll() {
|
||||||
|
return await context.Addresses.ToArrayAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<Address> Create(Address model) {
|
||||||
|
await context.Addresses.AddAsync(model);
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<Address> Update(Address model) {
|
||||||
|
context.Addresses.Update(model);
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task Delete(Address model) {
|
||||||
|
context.Addresses.Remove(model);
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
31
test/FrontendTest/Providers/EmployeeProvider.cs
Normal file
31
test/FrontendTest/Providers/EmployeeProvider.cs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
using HopFrame.Web.Admin;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using RestApiTest.Models;
|
||||||
|
|
||||||
|
namespace FrontendTest.Providers;
|
||||||
|
|
||||||
|
public class EmployeeProvider(DatabaseContext context) : ModelRepository<Employee> {
|
||||||
|
|
||||||
|
public override async Task<IEnumerable<Employee>> ReadAll() {
|
||||||
|
return await context.Employees
|
||||||
|
.Include(e => e.Address)
|
||||||
|
.ToArrayAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<Employee> Create(Employee model) {
|
||||||
|
await context.Employees.AddAsync(model);
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<Employee> Update(Employee model) {
|
||||||
|
context.Employees.Update(model);
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task Delete(Employee model) {
|
||||||
|
context.Employees.Remove(model);
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user