even more common
This commit is contained in:
parent
1d7e81c71d
commit
90d875ad02
103
Controllers/AutoChildController.cs
Normal file
103
Controllers/AutoChildController.cs
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using ApiSourceGeneratorHelper;
|
||||
using AutoMapPropertyHelper;
|
||||
using EntityFrameworkCore.Projectables;
|
||||
using EntityFrameworkCore.Projectables.Extensions;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.HttpResults;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NejCommon.Utils;
|
||||
using Swashbuckle.AspNetCore.Annotations;
|
||||
using NejCommon.Models;
|
||||
|
||||
namespace NejCommon.Controllers
|
||||
{
|
||||
public abstract class AutoChildController<TOwner, TType, TRequest, TResponse> : AutoChildController<TOwner, TType, TResponse, TRequest, TResponse>
|
||||
where TType : class, new()
|
||||
where TRequest : IAutomappedAttribute<TType, TRequest>, new()
|
||||
where TResponse : IAutomappedAttribute<TType, TResponse>, new()
|
||||
{
|
||||
public AutoChildController(CommonDbContext appDb, IServiceProvider providers) : base(appDb, providers)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="TType">The underyling type</typeparam>
|
||||
/// <typeparam name="TRequest">The request type</typeparam>
|
||||
/// <typeparam name="TResponse">The response type</typeparam>
|
||||
[ApiController]
|
||||
public abstract class AutoChildController<TOwner, TType, TGetResponse, TUpdateRequest, TUpdateResponse> : ControllerBase
|
||||
where TType : class, new()
|
||||
where TGetResponse : IAutomappedAttribute<TType, TGetResponse>, new()
|
||||
where TUpdateRequest : IAutomappedAttribute<TType, TUpdateRequest>, new()
|
||||
where TUpdateResponse : IAutomappedAttribute<TType, TUpdateResponse>, new()
|
||||
{
|
||||
protected readonly CommonDbContext db;
|
||||
protected readonly IServiceProvider providers;
|
||||
|
||||
public AutoChildController(CommonDbContext appDb, IServiceProvider providers) : base()
|
||||
{
|
||||
db = appDb;
|
||||
this.providers = providers;
|
||||
}
|
||||
|
||||
protected abstract TType GetQuery(TOwner comp);
|
||||
protected abstract void Assign(TOwner comp, TType query);
|
||||
public virtual bool Trackable => true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <typeparamref name="TType"/>
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <response code="200">Success</response>
|
||||
/// <response code="0">There was an error</response>
|
||||
[HttpGet]
|
||||
[Route("")]
|
||||
public virtual async Task<Results<NotFound, Ok<TGetResponse>>> Get([FromServices] TOwner owner)
|
||||
{
|
||||
var entity = GetQuery(owner);
|
||||
var dat = new TGetResponse().ApplyFrom(providers, entity);
|
||||
return TypedResults.Ok(dat);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update company.
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <param name="body"></param>
|
||||
/// <response code="200">Success</response>
|
||||
/// <response code="0">There was an error</response>
|
||||
[HttpPut]
|
||||
[Route("")]
|
||||
public virtual async Task<Results<NotFound, BadRequest<Error>, Ok<TUpdateResponse>>> Update([FromServices] TOwner owner, [FromBody] TUpdateRequest body)
|
||||
{
|
||||
var entity = GetQuery(owner);
|
||||
if (entity == null)
|
||||
{
|
||||
if (Trackable)
|
||||
entity = db.Create<TType>();
|
||||
else
|
||||
entity = new TType();
|
||||
Assign(owner, entity);
|
||||
}
|
||||
/*
|
||||
if(entity is InvoiceBase inv){
|
||||
//Console.Writeline(inv.InvoiceItems.Count);
|
||||
}*/
|
||||
body.ApplyTo(providers, entity);
|
||||
|
||||
var dat = new TUpdateResponse().ApplyFrom(providers, entity);
|
||||
|
||||
var res = await db.ApiSaveChangesAsyncOk<TType, TUpdateResponse>(providers, entity);
|
||||
|
||||
//use the private constructor thru reflection
|
||||
var ctor = typeof(Results<NotFound, BadRequest<Error>, Ok<TUpdateResponse>>).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)[0];
|
||||
return (Results<NotFound, BadRequest<Error>, Ok<TUpdateResponse>>)ctor.Invoke(new object[] { res.Result });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,26 +8,20 @@ using Microsoft.AspNetCore.Http;
|
|||
using Microsoft.AspNetCore.Http.HttpResults;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NejAccountingAPI.Controllers;
|
||||
using NejAccountingAPI.Models;
|
||||
using NejCommon.Utils;
|
||||
using Swashbuckle.AspNetCore.Annotations;
|
||||
using NejCommon.Models;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace NejCommon.Controllers
|
||||
{
|
||||
public abstract class AutoController<TType, TRequest, TResponse> : AutoController<Company, TType, TRequest, TResponse> where TType : class, new() where TRequest : IAutomappedAttribute<TType, TRequest>, new() where TResponse : IAutomappedAttribute<TType, TResponse>, new()
|
||||
{
|
||||
public AutoController(AppDbContext appDb, IServiceProvider providers) : base(appDb, providers)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class AutoController<TOwner, TType, TRequest, TResponse> : AutoController<TOwner, TType, TResponse, TRequest, TResponse, TResponse, TRequest, TResponse>
|
||||
where TType : class, new()
|
||||
where TRequest : IAutomappedAttribute<TType, TRequest>, new()
|
||||
where TResponse : IAutomappedAttribute<TType, TResponse>, new()
|
||||
{
|
||||
public AutoController(AppDbContext appDb, IServiceProvider providers) : base(appDb, providers)
|
||||
public AutoController(CommonDbContext appDb, IServiceProvider providers) : base(appDb, providers)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -39,7 +33,7 @@ namespace NejCommon.Controllers
|
|||
/// <typeparam name="TRequest">The request type</typeparam>
|
||||
/// <typeparam name="TResponse">The response type</typeparam>
|
||||
[ApiController]
|
||||
public abstract class AutoController<TOwner, TType, TGetAllResponse, TCreateRequest, TCreateResponse, TGetResponse, TUpdateRequest, TUpdateResponse> : ControllerBase
|
||||
public abstract partial class AutoController<TOwner, TType, TGetAllResponse, TCreateRequest, TCreateResponse, TGetResponse, TUpdateRequest, TUpdateResponse> : AutoGetterController<TOwner, TType, TGetAllResponse, TGetResponse>
|
||||
where TType : class, new()
|
||||
where TGetAllResponse : IAutomappedAttribute<TType, TGetAllResponse>, new()
|
||||
where TCreateRequest : IAutomappedAttribute<TType, TCreateRequest>, new()
|
||||
|
|
@ -48,24 +42,15 @@ namespace NejCommon.Controllers
|
|||
where TUpdateRequest : IAutomappedAttribute<TType, TUpdateRequest>, new()
|
||||
where TUpdateResponse : IAutomappedAttribute<TType, TUpdateResponse>, new()
|
||||
{
|
||||
protected readonly AppDbContext db;
|
||||
protected readonly IServiceProvider providers;
|
||||
|
||||
public AutoController(AppDbContext appDb, IServiceProvider providers) : base()
|
||||
public AutoController(CommonDbContext appDb, IServiceProvider providers) : base(appDb, providers)
|
||||
{
|
||||
db = appDb;
|
||||
this.providers = providers;
|
||||
|
||||
}
|
||||
|
||||
protected abstract IQueryable<TType> GetQuery(TOwner comp);
|
||||
protected virtual TType AssociateWithParent(TType entity, TOwner comp)
|
||||
{
|
||||
if (typeof(TOwner) != typeof(Company))
|
||||
{
|
||||
throw new NotImplementedException("Special parent association not implemented");
|
||||
}
|
||||
|
||||
var props = typeof(TType).GetProperty("Company");
|
||||
var props = typeof(TType).GetProperty(HelperMainName);
|
||||
if (props == null)
|
||||
{
|
||||
//not implemented
|
||||
|
|
@ -74,26 +59,6 @@ namespace NejCommon.Controllers
|
|||
props.SetValue(entity, comp);
|
||||
return entity;
|
||||
}
|
||||
protected virtual IQueryable<TType> ApplyDefaultOrdering(IQueryable<TType> query)
|
||||
{
|
||||
return query;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get all the <typeparamref name="TType"/>
|
||||
/// </summary>
|
||||
/// <response code="200">Success</response>
|
||||
/// <response code="0">There was an error</response>
|
||||
[HttpGet]
|
||||
public virtual async Task<Results<BadRequest<Error>, Ok<PaginationResponse<TGetAllResponse>>>> GetAll(TOwner company, [FromQuery] Pagination pag)
|
||||
{
|
||||
var data = await ApplyDefaultOrdering(GetQuery(company)).AsNoTrackingWithIdentityResolution().ApplyPaginationRes<TType, TGetAllResponse>(providers, pag);
|
||||
|
||||
//Console.Writeline(data.Data);
|
||||
|
||||
return TypedResults.Ok(data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the <typeparamref name="TType"/>
|
||||
|
|
@ -102,7 +67,7 @@ namespace NejCommon.Controllers
|
|||
/// <response code="201">Success</response>
|
||||
/// <response code="0">There was an error</response>
|
||||
[HttpPost]
|
||||
public virtual async Task<Results<BadRequest<Error>, CreatedAtRoute<TCreateResponse>>> Create(TOwner company, [FromBody] TCreateRequest body)
|
||||
public virtual async Task<Results<BadRequest<Error>, CreatedAtRoute<TCreateResponse>>> Create([FromServices] TOwner company, [FromBody] TCreateRequest body)
|
||||
{
|
||||
var entity = db.Create<TType>();
|
||||
|
||||
|
|
@ -115,20 +80,6 @@ namespace NejCommon.Controllers
|
|||
return await db.ApiSaveChangesAsyncCreate<TType, TCreateResponse>(providers, entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <typeparamref name="TType"/>
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <response code="200">Success</response>
|
||||
/// <response code="0">There was an error</response>
|
||||
[HttpGet]
|
||||
[Route("{id}/")]
|
||||
public virtual async Task<Results<NotFound, Ok<TGetResponse>>> Get([FromServices][ModelBinder(Name = "id")] TType entity)
|
||||
{
|
||||
var dat = new TGetResponse().ApplyFrom(providers, entity);
|
||||
return TypedResults.Ok(dat);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete company.
|
||||
/// </summary>
|
||||
|
|
@ -154,10 +105,7 @@ namespace NejCommon.Controllers
|
|||
[HttpPut]
|
||||
[Route("{id}/")]
|
||||
public virtual async Task<Results<NotFound, BadRequest<Error>, Ok<TUpdateResponse>>> Update([FromServices][ModelBinder(Name = "id")] TType entity, [FromBody] TUpdateRequest body)
|
||||
{/*
|
||||
if(entity is InvoiceBase inv){
|
||||
//Console.Writeline(inv.InvoiceItems.Count);
|
||||
}*/
|
||||
{
|
||||
body.ApplyTo(providers, entity);
|
||||
|
||||
var dat = new TUpdateResponse().ApplyFrom(providers, entity);
|
||||
|
|
@ -169,4 +117,55 @@ namespace NejCommon.Controllers
|
|||
return (Results<NotFound, BadRequest<Error>, Ok<TUpdateResponse>>)ctor.Invoke(new object[] { res.Result });
|
||||
}
|
||||
}
|
||||
[ApiController]
|
||||
public abstract class AutoGetterController<TOwner, TType, TGetAllResponse, TGetResponse> : ControllerBase
|
||||
where TType : class, new()
|
||||
where TGetAllResponse : IAutomappedAttribute<TType, TGetAllResponse>, new()
|
||||
where TGetResponse : IAutomappedAttribute<TType, TGetResponse>, new()
|
||||
{
|
||||
protected readonly CommonDbContext db;
|
||||
protected readonly IServiceProvider providers;
|
||||
|
||||
public AutoGetterController(CommonDbContext appDb, IServiceProvider providers) : base()
|
||||
{
|
||||
db = appDb;
|
||||
this.providers = providers;
|
||||
}
|
||||
|
||||
protected abstract IQueryable<TType> GetQuery(TOwner comp);
|
||||
|
||||
protected virtual IQueryable<TType> ApplyDefaultOrdering(IQueryable<TType> query)
|
||||
{
|
||||
return query;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get all the <typeparamref name="TType"/>
|
||||
/// </summary>
|
||||
/// <response code="200">Success</response>
|
||||
/// <response code="0">There was an error</response>
|
||||
[HttpGet]
|
||||
public virtual async Task<Results<BadRequest<Error>, Ok<PaginationResponse<TGetAllResponse>>>> GetAll([FromServices] TOwner company, [FromQuery] Pagination pag)
|
||||
{
|
||||
var data = await ApplyDefaultOrdering(GetQuery(company)).AsNoTrackingWithIdentityResolution().ApplyPaginationRes<TType, TGetAllResponse>(providers, pag);
|
||||
|
||||
//Console.Writeline(data.Data);
|
||||
|
||||
return TypedResults.Ok(data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <typeparamref name="TType"/>
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <response code="200">Success</response>
|
||||
/// <response code="0">There was an error</response>
|
||||
[HttpGet]
|
||||
[Route("{id}/")]
|
||||
public virtual async Task<Results<NotFound, Ok<TGetResponse>>> Get([FromServices][ModelBinder(Name = "id")] TType entity)
|
||||
{
|
||||
var dat = new TGetResponse().ApplyFrom(providers, entity);
|
||||
return TypedResults.Ok(dat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
! tailwindcss v3.2.4 | MIT License | https://tailwindcss.com
|
||||
! tailwindcss v3.4.11 | MIT License | https://tailwindcss.com
|
||||
*/
|
||||
|
||||
/*
|
||||
|
|
@ -31,9 +31,12 @@
|
|||
3. Use a more readable tab size.
|
||||
4. Use the user's configured `sans` font-family by default.
|
||||
5. Use the user's configured `sans` font-feature-settings by default.
|
||||
6. Use the user's configured `sans` font-variation-settings by default.
|
||||
7. Disable tap highlights on iOS
|
||||
*/
|
||||
|
||||
html {
|
||||
html,
|
||||
:host {
|
||||
line-height: 1.5;
|
||||
/* 1 */
|
||||
-webkit-text-size-adjust: 100%;
|
||||
|
|
@ -43,10 +46,14 @@ html {
|
|||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
/* 3 */
|
||||
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
/* 4 */
|
||||
font-feature-settings: normal;
|
||||
/* 5 */
|
||||
font-variation-settings: normal;
|
||||
/* 6 */
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
/* 7 */
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -118,8 +125,10 @@ strong {
|
|||
}
|
||||
|
||||
/*
|
||||
1. Use the user's configured `mono` font family by default.
|
||||
2. Correct the odd `em` font sizing in all browsers.
|
||||
1. Use the user's configured `mono` font-family by default.
|
||||
2. Use the user's configured `mono` font-feature-settings by default.
|
||||
3. Use the user's configured `mono` font-variation-settings by default.
|
||||
4. Correct the odd `em` font sizing in all browsers.
|
||||
*/
|
||||
|
||||
code,
|
||||
|
|
@ -128,8 +137,12 @@ samp,
|
|||
pre {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
/* 1 */
|
||||
font-size: 1em;
|
||||
font-feature-settings: normal;
|
||||
/* 2 */
|
||||
font-variation-settings: normal;
|
||||
/* 3 */
|
||||
font-size: 1em;
|
||||
/* 4 */
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -188,12 +201,18 @@ select,
|
|||
textarea {
|
||||
font-family: inherit;
|
||||
/* 1 */
|
||||
font-feature-settings: inherit;
|
||||
/* 1 */
|
||||
font-variation-settings: inherit;
|
||||
/* 1 */
|
||||
font-size: 100%;
|
||||
/* 1 */
|
||||
font-weight: inherit;
|
||||
/* 1 */
|
||||
line-height: inherit;
|
||||
/* 1 */
|
||||
letter-spacing: inherit;
|
||||
/* 1 */
|
||||
color: inherit;
|
||||
/* 1 */
|
||||
margin: 0;
|
||||
|
|
@ -217,9 +236,9 @@ select {
|
|||
*/
|
||||
|
||||
button,
|
||||
[type='button'],
|
||||
[type='reset'],
|
||||
[type='submit'] {
|
||||
input:where([type='button']),
|
||||
input:where([type='reset']),
|
||||
input:where([type='submit']) {
|
||||
-webkit-appearance: button;
|
||||
/* 1 */
|
||||
background-color: transparent;
|
||||
|
|
@ -338,6 +357,14 @@ menu {
|
|||
padding: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Reset default styling for dialogs.
|
||||
*/
|
||||
|
||||
dialog {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Prevent resizing textareas horizontally by default.
|
||||
*/
|
||||
|
|
@ -433,6 +460,9 @@ video {
|
|||
--tw-pan-y: ;
|
||||
--tw-pinch-zoom: ;
|
||||
--tw-scroll-snap-strictness: proximity;
|
||||
--tw-gradient-from-position: ;
|
||||
--tw-gradient-via-position: ;
|
||||
--tw-gradient-to-position: ;
|
||||
--tw-ordinal: ;
|
||||
--tw-slashed-zero: ;
|
||||
--tw-numeric-figure: ;
|
||||
|
|
@ -464,6 +494,10 @@ video {
|
|||
--tw-backdrop-opacity: ;
|
||||
--tw-backdrop-saturate: ;
|
||||
--tw-backdrop-sepia: ;
|
||||
--tw-contain-size: ;
|
||||
--tw-contain-layout: ;
|
||||
--tw-contain-paint: ;
|
||||
--tw-contain-style: ;
|
||||
}
|
||||
|
||||
::backdrop {
|
||||
|
|
@ -480,6 +514,9 @@ video {
|
|||
--tw-pan-y: ;
|
||||
--tw-pinch-zoom: ;
|
||||
--tw-scroll-snap-strictness: proximity;
|
||||
--tw-gradient-from-position: ;
|
||||
--tw-gradient-via-position: ;
|
||||
--tw-gradient-to-position: ;
|
||||
--tw-ordinal: ;
|
||||
--tw-slashed-zero: ;
|
||||
--tw-numeric-figure: ;
|
||||
|
|
@ -511,234 +548,28 @@ video {
|
|||
--tw-backdrop-opacity: ;
|
||||
--tw-backdrop-saturate: ;
|
||||
--tw-backdrop-sepia: ;
|
||||
--tw-contain-size: ;
|
||||
--tw-contain-layout: ;
|
||||
--tw-contain-paint: ;
|
||||
--tw-contain-style: ;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.container {
|
||||
max-width: 640px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.container {
|
||||
max-width: 768px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.container {
|
||||
max-width: 1024px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1280px) {
|
||||
.container {
|
||||
max-width: 1280px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1536px) {
|
||||
.container {
|
||||
max-width: 1536px;
|
||||
}
|
||||
.visible {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.static {
|
||||
position: static;
|
||||
}
|
||||
|
||||
.ml-2 {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.inline {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.table {
|
||||
display: table;
|
||||
}
|
||||
|
||||
.h-full {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.h-16 {
|
||||
height: 4rem;
|
||||
}
|
||||
|
||||
.h-48 {
|
||||
height: 12rem;
|
||||
}
|
||||
|
||||
.w-full {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.w-16 {
|
||||
width: 4rem;
|
||||
}
|
||||
|
||||
.w-48 {
|
||||
width: 12rem;
|
||||
}
|
||||
|
||||
.flex-grow {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.flex-col {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.flex-wrap {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.items-end {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.items-center {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.justify-end {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.justify-center {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.justify-between {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.self-end {
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
.rounded-md {
|
||||
border-radius: 0.375rem;
|
||||
}
|
||||
|
||||
.rounded {
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.border-4 {
|
||||
border-width: 4px;
|
||||
}
|
||||
|
||||
.bg-primary {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(var(--primary) / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.py-2 {
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.py-4 {
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.px-10 {
|
||||
padding-left: 2.5rem;
|
||||
padding-right: 2.5rem;
|
||||
}
|
||||
|
||||
.pt-2 {
|
||||
padding-top: 0.5rem;
|
||||
}
|
||||
|
||||
.pb-2 {
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.pl-8 {
|
||||
padding-left: 2rem;
|
||||
}
|
||||
|
||||
.pr-8 {
|
||||
padding-right: 2rem;
|
||||
}
|
||||
|
||||
.pr-4 {
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
.pt-1 {
|
||||
padding-top: 0.25rem;
|
||||
}
|
||||
|
||||
.text-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.text-sm {
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
|
||||
.text-xs {
|
||||
font-size: 0.75rem;
|
||||
line-height: 1rem;
|
||||
}
|
||||
|
||||
.text-lg {
|
||||
font-size: 1.125rem;
|
||||
line-height: 1.75rem;
|
||||
}
|
||||
|
||||
.text-3xl {
|
||||
font-size: 1.875rem;
|
||||
line-height: 2.25rem;
|
||||
}
|
||||
|
||||
.text-xl {
|
||||
font-size: 1.25rem;
|
||||
line-height: 1.75rem;
|
||||
}
|
||||
|
||||
.text-2xl {
|
||||
font-size: 1.5rem;
|
||||
line-height: 2rem;
|
||||
}
|
||||
|
||||
.font-semibold {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.font-bold {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.text-secondary {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(var(--secondary-text) / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.text-primary {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(var(--primary-text) / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.filter {
|
||||
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@ using Microsoft.EntityFrameworkCore;
|
|||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using NejAccountingAPI.Documents;
|
||||
using NejAccountingAPI.Models;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
|
@ -54,7 +52,7 @@ namespace NejCommon.Models
|
|||
|
||||
public abstract class EntityBinder<TEntity> : EntityBinder<TEntity, string> where TEntity : class
|
||||
{
|
||||
public EntityBinder(AppDbContext db, RouteValue<TEntity>[] routeValues) : base(db, routeValues)
|
||||
public EntityBinder(DbContext db, RouteValue<TEntity>[] routeValues) : base(db, routeValues)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -65,13 +63,13 @@ namespace NejCommon.Models
|
|||
where TEntity : class
|
||||
where TIdType : IEquatable<TIdType>
|
||||
{
|
||||
private readonly AppDbContext _db;
|
||||
private readonly DbContext _db;
|
||||
private readonly RouteValue<TEntity>[] _routeValues;
|
||||
|
||||
public RouteValue<TEntity>[] RouteValues => _routeValues;
|
||||
|
||||
|
||||
public EntityBinder(AppDbContext db, RouteValue<TEntity>[] routeValues)
|
||||
public EntityBinder(DbContext db, RouteValue<TEntity>[] routeValues)
|
||||
{
|
||||
_db = db;
|
||||
_routeValues = routeValues;
|
||||
|
|
|
|||
145
Models/CommonDbContext.cs
Normal file
145
Models/CommonDbContext.cs
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
|
||||
|
||||
using System.Globalization;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using AutoMapPropertyHelper;
|
||||
using EntityFrameworkCore.Projectables;
|
||||
using Microsoft.AspNetCore.Http.HttpResults;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace NejCommon.Models;
|
||||
|
||||
|
||||
public abstract class CommonDbContext : DbContext
|
||||
{
|
||||
public CommonDbContext() : base()
|
||||
{
|
||||
}
|
||||
public CommonDbContext(DbContextOptions options)
|
||||
: base(options)
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<bool> ApiSaveChangesAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
await SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Error saving db: " + ex.Message);
|
||||
Console.WriteLine(ex.StackTrace);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static BadRequest<Error> SaveError = TypedResults.BadRequest(new Error
|
||||
{
|
||||
Message = "Error saving data to database"
|
||||
});
|
||||
|
||||
public async Task<Results<BadRequest<Error>, T1>> ApiSaveChangesAsync<T1>(T1 value) where T1 : IResult
|
||||
{
|
||||
var res = await ApiSaveChangesAsync();
|
||||
|
||||
if (res)
|
||||
return value;
|
||||
else
|
||||
return SaveError;
|
||||
}
|
||||
public async Task<Results<BadRequest<Error>, CreatedAtRoute<T2>>> ApiSaveChangesAsyncCreate<T1, T2>(IServiceProvider providers, T1 value, bool apply = true) where T2 : IAutomappedAttribute<T1, T2>, new()
|
||||
{
|
||||
if (!apply)
|
||||
return TypedResults.CreatedAtRoute(new T2().ApplyFrom(providers, value));
|
||||
|
||||
var res = await ApiSaveChangesAsync();
|
||||
|
||||
if (res)
|
||||
return TypedResults.CreatedAtRoute(new T2().ApplyFrom(providers, value));
|
||||
else
|
||||
return SaveError;
|
||||
}
|
||||
public async Task<Results<BadRequest<Error>, Ok<T2>>> ApiSaveChangesAsyncOk<T1, T2>(IServiceProvider providers, T1 value, bool apply = true) where T2 : IAutomappedAttribute<T1, T2>, new()
|
||||
{
|
||||
if (!apply)
|
||||
return TypedResults.Ok(new T2().ApplyFrom(providers, value));
|
||||
|
||||
var res = await ApiSaveChangesAsync();
|
||||
|
||||
if (res)
|
||||
return TypedResults.Ok(new T2().ApplyFrom(providers, value));
|
||||
else
|
||||
return SaveError;
|
||||
}
|
||||
public async Task<T> FindOrCreateAsync<T>(Expression<Func<T, bool>> predicate, Func<T> factory) where T : class
|
||||
{
|
||||
var entity = ChangeTracker.Entries<T>().Select(x => x.Entity).FirstOrDefault(predicate.Compile());
|
||||
|
||||
if (entity != null && Entry(entity).State == EntityState.Deleted)
|
||||
{
|
||||
Entry(entity).State = EntityState.Modified;
|
||||
}
|
||||
|
||||
if (entity == null)
|
||||
{
|
||||
entity = await Set<T>().FirstOrDefaultAsync(predicate);
|
||||
}
|
||||
|
||||
if (entity == null)
|
||||
{
|
||||
var newAppDB = Activator.CreateInstance(this.GetType()) as CommonDbContext;
|
||||
|
||||
entity = await newAppDB.Set<T>().FirstOrDefaultAsync(predicate);
|
||||
|
||||
//track the entity if it's not null and not already being tracked
|
||||
if (entity != null && this.Entry(entity).State == EntityState.Detached)
|
||||
Attach(entity);
|
||||
}
|
||||
if (entity == null)
|
||||
{
|
||||
var newEntity = factory();
|
||||
await this.AddAsync(newEntity);
|
||||
entity = newEntity;
|
||||
}
|
||||
|
||||
return entity;
|
||||
}
|
||||
public T FindOrCreate<T>(Expression<Func<T, bool>> predicate, Func<T> factory) where T : class
|
||||
{
|
||||
var entity = ChangeTracker.Entries<T>().Where(e => e.State != EntityState.Deleted).Select(x => x.Entity).FirstOrDefault(predicate.Compile());
|
||||
//var entity = this.;
|
||||
if (entity == null)
|
||||
{
|
||||
var newAppDB = Activator.CreateInstance(this.GetType()) as CommonDbContext;
|
||||
|
||||
entity = newAppDB.Set<T>().FirstOrDefault(predicate);
|
||||
if (entity != null)
|
||||
Attach(entity);
|
||||
}
|
||||
if (entity == null)
|
||||
{
|
||||
var newEntity = factory();
|
||||
this.Add(newEntity);
|
||||
entity = newEntity;
|
||||
}
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
public T Create<T>(Action<T> config = null, params object[] constructorArguments)
|
||||
{
|
||||
var entity = this.CreateProxy<T>(constructorArguments);
|
||||
|
||||
config?.Invoke(entity);
|
||||
this.Add(entity);
|
||||
return entity;
|
||||
}
|
||||
|
||||
public void ApplyRelationships()
|
||||
{
|
||||
this.ChangeTracker.DetectChanges();
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,6 @@ using AutoMapPropertyHelper;
|
|||
using EntityFrameworkCore.Projectables;
|
||||
using EntityFrameworkCore.Projectables.Extensions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NejAccountingAPI.Models;
|
||||
using NejCommon.Controllers;
|
||||
using NejCommon.Models;
|
||||
|
||||
|
|
@ -56,7 +55,7 @@ public static class Extensions
|
|||
}
|
||||
|
||||
var extPar = Expression.Parameter(typeof(TType));
|
||||
var binder = (TEntityBinder)typeof(TEntityBinder).GetConstructor(new[] { typeof(AppDbContext) })!.Invoke(new object?[] { null });
|
||||
var binder = (TEntityBinder)typeof(TEntityBinder).GetConstructor(new[] { typeof(DbContext) })!.Invoke(new object?[] { null });
|
||||
var idMatcher = binder.RouteValues.First(x => x.Primary).Expression;
|
||||
var reducedIdMatcher = Expression.Lambda<Func<TType, bool>>(Expression.Invoke(idMatcher, extPar, Expression.Constant(search)).Reduce(), extPar);
|
||||
//Console.Writeline(reducedIdMatcher);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user