diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000000..4c276999f1
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,31 @@
+language: csharp
+sudo: required
+dist: trusty
+env:
+ - CLI_VERSION=latest
+addons:
+ apt:
+ packages:
+ - gettext
+ - libcurl4-openssl-dev
+ - libicu-dev
+ - libssl-dev
+ - libunwind8
+ - zlib1g
+mono:
+ - 4.2.3
+os:
+ - linux
+ - osx
+osx_image: xcode7.1
+branches:
+ only:
+ - master
+before_install:
+ - if test "$TRAVIS_OS_NAME" = "osx"; then brew update; brew install openssl; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; fi
+install:
+ - export DOTNET_INSTALL_DIR="$PWD/.dotnetcli"
+ - curl -sSL https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0/scripts/obtain/dotnet-install.sh | bash /dev/stdin --version "$CLI_VERSION" --install-dir "$DOTNET_INSTALL_DIR"
+ - export PATH="$DOTNET_INSTALL_DIR:$PATH"
+script:
+ - ./build.sh
diff --git a/Build.ps1 b/Build.ps1
new file mode 100644
index 0000000000..fb3f5a6317
--- /dev/null
+++ b/Build.ps1
@@ -0,0 +1,64 @@
+<#
+.SYNOPSIS
+ You can add this to you build script to ensure that psbuild is available before calling
+ Invoke-MSBuild. If psbuild is not available locally it will be downloaded automatically.
+#>
+function EnsurePsbuildInstalled{
+ [cmdletbinding()]
+ param(
+ [string]$psbuildInstallUri = 'https://raw.githubusercontent.com/ligershark/psbuild/master/src/GetPSBuild.ps1'
+ )
+ process{
+ if(-not (Get-Command "Invoke-MsBuild" -errorAction SilentlyContinue)){
+ 'Installing psbuild from [{0}]' -f $psbuildInstallUri | Write-Verbose
+ (new-object Net.WebClient).DownloadString($psbuildInstallUri) | iex
+ }
+ else{
+ 'psbuild already loaded, skipping download' | Write-Verbose
+ }
+
+ # make sure it's loaded and throw if not
+ if(-not (Get-Command "Invoke-MsBuild" -errorAction SilentlyContinue)){
+ throw ('Unable to install/load psbuild from [{0}]' -f $psbuildInstallUri)
+ }
+ }
+}
+
+# Taken from psake https://github.com/psake/psake
+
+<#
+.SYNOPSIS
+ This is a helper function that runs a scriptblock and checks the PS variable $lastexitcode
+ to see if an error occcured. If an error is detected then an exception is thrown.
+ This function allows you to run command-line programs without having to
+ explicitly check the $lastexitcode variable.
+.EXAMPLE
+ exec { svn info $repository_trunk } "Error executing SVN. Please verify SVN command-line client is installed"
+#>
+function Exec
+{
+ [CmdletBinding()]
+ param(
+ [Parameter(Position=0,Mandatory=1)][scriptblock]$cmd,
+ [Parameter(Position=1,Mandatory=0)][string]$errorMessage = ($msgs.error_bad_command -f $cmd)
+ )
+ & $cmd
+ if ($lastexitcode -ne 0) {
+ throw ("Exec: " + $errorMessage)
+ }
+}
+
+if(Test-Path .\artifacts) { Remove-Item .\artifacts -Force -Recurse }
+
+EnsurePsbuildInstalled
+
+exec { & dotnet restore }
+
+Invoke-MSBuild
+
+$revision = @{ $true = $env:APPVEYOR_BUILD_NUMBER; $false = 1 }[$env:APPVEYOR_BUILD_NUMBER -ne $NULL];
+$revision = "{0:D4}" -f [convert]::ToInt32($revision, 10)
+
+exec { & dotnet test .\JsonApiDotNetCoreTests -c Release }
+
+exec { & dotnet pack .\JsonApiDotNetCore -c Release -o .\artifacts --version-suffix=$revision }
diff --git a/JsonApiDotNetCore/Abstractions/IJsonApiContext.cs b/JsonApiDotNetCore/Abstractions/IJsonApiContext.cs
new file mode 100644
index 0000000000..7c3bdcc410
--- /dev/null
+++ b/JsonApiDotNetCore/Abstractions/IJsonApiContext.cs
@@ -0,0 +1,18 @@
+using System;
+using JsonApiDotNetCore.Configuration;
+using JsonApiDotNetCore.Routing;
+using Microsoft.AspNetCore.Http;
+
+namespace JsonApiDotNetCore.Abstractions
+{
+ public interface IJsonApiContext
+ {
+ JsonApiModelConfiguration Configuration { get; }
+ object DbContext { get; }
+ HttpContext HttpContext { get; }
+ Route Route { get; }
+ string GetEntityName();
+ Type GetEntityType();
+ Type GetJsonApiResourceType();
+ }
+}
diff --git a/JsonApiDotNetCore/Abstractions/JsonApiContext.cs b/JsonApiDotNetCore/Abstractions/JsonApiContext.cs
index 9a18bf0375..d2eb00f819 100644
--- a/JsonApiDotNetCore/Abstractions/JsonApiContext.cs
+++ b/JsonApiDotNetCore/Abstractions/JsonApiContext.cs
@@ -7,7 +7,7 @@
namespace JsonApiDotNetCore.Abstractions
{
- public class JsonApiContext
+ public class JsonApiContext : IJsonApiContext
{
public HttpContext HttpContext { get; }
public Route Route { get; }
@@ -24,7 +24,7 @@ public JsonApiContext(HttpContext httpContext, Route route, object dbContext, Js
public Type GetJsonApiResourceType()
{
- return Configuration.ResourceMapDefinitions[Route.BaseModelType];
+ return Configuration.ResourceMapDefinitions[Route.BaseModelType].Item1;
}
public string GetEntityName()
diff --git a/JsonApiDotNetCore/Configuration/IJsonApiModelConfiguration.cs b/JsonApiDotNetCore/Configuration/IJsonApiModelConfiguration.cs
index 583a5f359d..cdb9aefeb5 100644
--- a/JsonApiDotNetCore/Configuration/IJsonApiModelConfiguration.cs
+++ b/JsonApiDotNetCore/Configuration/IJsonApiModelConfiguration.cs
@@ -1,13 +1,41 @@
using System;
using System.Collections.Generic;
using AutoMapper;
+using JsonApiDotNetCore.Abstractions;
namespace JsonApiDotNetCore.Configuration
{
public interface IJsonApiModelConfiguration
{
+ ///
+ /// The database context to use
+ ///
+ ///
+ ///
void UseContext();
+
+ ///
+ /// The request namespace.
+ ///
+ ///
+ /// api/v1
void SetDefaultNamespace(string ns);
- void DefineResourceMapping(Action> mapping);
+
+ ///
+ /// Define explicit mapping of a model to a class that implements IJsonApiResource
+ ///
+ ///
+ ///
+ ///
+ ///
+ void AddResourceMapping(Action mappingExpression);
+
+ ///
+ /// Specifies a controller override class for a particular model type.
+ ///
+ ///
+ ///
+ ///
+ void UseController();
}
}
diff --git a/JsonApiDotNetCore/Configuration/JsonApiConfigurationBuilder.cs b/JsonApiDotNetCore/Configuration/JsonApiConfigurationBuilder.cs
new file mode 100644
index 0000000000..4debb4d227
--- /dev/null
+++ b/JsonApiDotNetCore/Configuration/JsonApiConfigurationBuilder.cs
@@ -0,0 +1,96 @@
+using System;
+using System.Reflection;
+using JsonApiDotNetCore.Routing;
+using Microsoft.EntityFrameworkCore;
+using System.Linq;
+using System.Linq.Expressions;
+using AutoMapper;
+using JsonApiDotNetCore.Abstractions;
+using JsonApiDotNetCore.Attributes;
+
+namespace JsonApiDotNetCore.Configuration
+{
+ public class JsonApiConfigurationBuilder
+ {
+ private readonly Action _configurationAction;
+ private JsonApiModelConfiguration Config { get; set; }
+
+ public JsonApiConfigurationBuilder(Action configurationAction)
+ {
+ Config = new JsonApiModelConfiguration();
+ _configurationAction = configurationAction;
+ }
+
+ public JsonApiModelConfiguration Build()
+ {
+ Config = new JsonApiModelConfiguration();
+ _configurationAction.Invoke(Config);
+ CheckIsValidConfiguration();
+ LoadModelRoutesFromContext();
+ SetupResourceMaps();
+ return Config;
+ }
+
+ private void CheckIsValidConfiguration()
+ {
+ if (Config.ContextType == null)
+ throw new NullReferenceException("DbContext is not specified");
+ }
+
+ private void LoadModelRoutesFromContext()
+ {
+ // Assumption: all DbSet<> types should be included in the route list
+ var properties = Config.ContextType.GetProperties().ToList();
+
+ properties.ForEach(property =>
+ {
+ if (property.PropertyType.GetTypeInfo().IsGenericType &&
+ property.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>))
+ {
+
+ var modelType = property.PropertyType.GetGenericArguments()[0];
+
+ var route = new RouteDefinition
+ {
+ ModelType = modelType,
+ PathString = RouteBuilder.BuildRoute(Config.Namespace, property.Name),
+ ContextPropertyName = property.Name
+ };
+
+ Config.Routes.Add(route);
+ }
+ });
+ }
+
+ private void SetupResourceMaps()
+ {
+ LoadDefaultResourceMaps();
+ var mapConfiguration = new MapperConfiguration(cfg =>
+ {
+ foreach (var definition in Config.ResourceMapDefinitions)
+ {
+ var mappingExpression = cfg.CreateMap(definition.Key, definition.Value.Item1);
+ definition.Value.Item2?.Invoke(mappingExpression);
+ }
+ });
+ Config.ResourceMapper = mapConfiguration.CreateMapper();
+ }
+
+ private void LoadDefaultResourceMaps()
+ {
+ var resourceAttribute = typeof(JsonApiResourceAttribute);
+ var modelTypes = Assembly.GetEntryAssembly().DefinedTypes.Where(t => t.GetCustomAttributes(resourceAttribute).Count() == 1);
+
+ foreach (var modelType in modelTypes)
+ {
+ var resourceType = ((JsonApiResourceAttribute)modelType.GetCustomAttribute(resourceAttribute)).JsonApiResourceType;
+
+ // do not overwrite custom definitions
+ if(!Config.ResourceMapDefinitions.ContainsKey(modelType.UnderlyingSystemType))
+ {
+ Config.ResourceMapDefinitions.Add(modelType.UnderlyingSystemType, new Tuple>(resourceType, null));
+ }
+ }
+ }
+ }
+}
diff --git a/JsonApiDotNetCore/Configuration/JsonApiModelConfiguration.cs b/JsonApiDotNetCore/Configuration/JsonApiModelConfiguration.cs
index e4c194908b..ad7feb42c4 100644
--- a/JsonApiDotNetCore/Configuration/JsonApiModelConfiguration.cs
+++ b/JsonApiDotNetCore/Configuration/JsonApiModelConfiguration.cs
@@ -3,6 +3,8 @@
using System.Linq;
using System.Reflection;
using AutoMapper;
+using JsonApiDotNetCore.Abstractions;
+using JsonApiDotNetCore.Controllers;
using JsonApiDotNetCore.JsonApi;
using JsonApiDotNetCore.Routing;
using Microsoft.AspNetCore.Http;
@@ -16,59 +18,42 @@ public class JsonApiModelConfiguration : IJsonApiModelConfiguration
public IMapper ResourceMapper;
public Type ContextType { get; set; }
public List Routes = new List();
- public Dictionary ResourceMapDefinitions = new Dictionary();
+ public Dictionary>> ResourceMapDefinitions = new Dictionary>>();
+ public Dictionary ControllerOverrides = new Dictionary();
public void SetDefaultNamespace(string ns)
{
Namespace = ns;
}
- public void DefineResourceMapping(Action> mapping)
+ public void AddResourceMapping(Action mappingExpression)
{
- mapping.Invoke(ResourceMapDefinitions);
+ var resourceType = typeof(TResource);
+ var modelType = typeof(TModel);
- var mapConfiguration = new MapperConfiguration(cfg =>
- {
- foreach (var definition in ResourceMapDefinitions)
- {
- cfg.CreateMap(definition.Key, definition.Value);
- }
- });
+ if (!resourceType.GetInterfaces().Contains(typeof(IJsonApiResource)))
+ throw new ArgumentException("Specified type does not implement IJsonApiResource", nameof(resourceType));
- ResourceMapper = mapConfiguration.CreateMapper();
+ ResourceMapDefinitions.Add(modelType, new Tuple>(resourceType, mappingExpression));
}
- public void UseContext()
- {
- // TODO: assert the context is of type DbContext
- ContextType = typeof(T);
- LoadModelRoutesFromContext();
- }
-
- private void LoadModelRoutesFromContext()
+ public void UseController()
{
- // Assumption: all DbSet<> types should be included in the route list
- var properties = ContextType.GetProperties().ToList();
+ var modelType = typeof(TModel);
+ var controllerType = typeof(TController);
- properties.ForEach(property =>
- {
- if (property.PropertyType.GetTypeInfo().IsGenericType &&
- property.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>))
- {
+ if (!controllerType.GetInterfaces().Contains(typeof(IJsonApiController)))
+ throw new ArgumentException("Specified type does not implement IJsonApiController", nameof(controllerType));
- var modelType = property.PropertyType.GetGenericArguments()[0];
+ ControllerOverrides[modelType] = controllerType;
+ }
- var route = new RouteDefinition
- {
- ModelType = modelType,
- PathString = RouteBuilder.BuildRoute(Namespace, property.Name),
- ContextPropertyName = property.Name
- };
+ public void UseContext()
+ {
+ ContextType = typeof(T);
- Routes.Add(route);
- }
- });
+ if (!typeof(DbContext).IsAssignableFrom(ContextType))
+ throw new ArgumentException("Context Type must derive from DbContext", nameof(T));
}
-
}
}
diff --git a/JsonApiDotNetCore/Controllers/ControllerBuilder.cs b/JsonApiDotNetCore/Controllers/ControllerBuilder.cs
index 78745bca8b..68d2d62b74 100644
--- a/JsonApiDotNetCore/Controllers/ControllerBuilder.cs
+++ b/JsonApiDotNetCore/Controllers/ControllerBuilder.cs
@@ -1,13 +1,45 @@
-using JsonApiDotNetCore.Abstractions;
+using System;
+using System.Reflection;
+using System.Linq;
+using JsonApiDotNetCore.Abstractions;
using JsonApiDotNetCore.Data;
namespace JsonApiDotNetCore.Controllers
{
public class ControllerBuilder : IControllerBuilder
{
+ private JsonApiContext _context { get; set; }
public IJsonApiController BuildController(JsonApiContext context)
{
- return new JsonApiController(context, new ResourceRepository(context));
+ _context = context;
+ var overrideController = GetOverrideController();
+ return overrideController ?? new JsonApiController(_context, new ResourceRepository(_context));
+ }
+
+ public IJsonApiController GetOverrideController()
+ {
+ Type controllerType;
+ return _context.Configuration.ControllerOverrides.TryGetValue(_context.GetEntityType(), out controllerType) ?
+ InstantiateController(controllerType) : null;
+ }
+
+ private IJsonApiController InstantiateController(Type controllerType)
+ {
+ var constructor = controllerType.GetConstructors()[0];
+ var parameters = constructor.GetParameters();
+ var services =
+ parameters.Select(param => GetService(param.ParameterType)).ToArray();
+ return (IJsonApiController) Activator.CreateInstance(controllerType, services);
+ }
+
+ private object GetService(Type serviceType)
+ {
+ if(serviceType == typeof(ResourceRepository))
+ return new ResourceRepository(_context);
+ if (serviceType == typeof(JsonApiContext))
+ return _context;
+
+ return _context.HttpContext.RequestServices.GetService(serviceType);
}
}
}
diff --git a/JsonApiDotNetCore/Controllers/JsonApiController.cs b/JsonApiDotNetCore/Controllers/JsonApiController.cs
index a776e85ed0..0b6f14ba7a 100644
--- a/JsonApiDotNetCore/Controllers/JsonApiController.cs
+++ b/JsonApiDotNetCore/Controllers/JsonApiController.cs
@@ -8,25 +8,25 @@ namespace JsonApiDotNetCore.Controllers
{
public class JsonApiController : IJsonApiController
{
- protected readonly JsonApiContext JsonApiContext;
+ protected readonly IJsonApiContext JsonApiContext;
private readonly ResourceRepository _resourceRepository;
- public JsonApiController(JsonApiContext jsonApiContext, ResourceRepository resourceRepository)
+ public JsonApiController(IJsonApiContext jsonApiContext, ResourceRepository resourceRepository)
{
JsonApiContext = jsonApiContext;
_resourceRepository = resourceRepository;
}
- public ObjectResult Get()
+ public virtual ObjectResult Get()
{
var entities = _resourceRepository.Get();
- if(entities == null || entities.Count == 0) {
+ if(entities == null) {
return new NotFoundObjectResult(null);
}
return new OkObjectResult(entities);
}
- public ObjectResult Get(string id)
+ public virtual ObjectResult Get(string id)
{
var entity = _resourceRepository.Get(id);
if(entity == null) {
@@ -35,14 +35,14 @@ public ObjectResult Get(string id)
return new OkObjectResult(entity);
}
- public ObjectResult Post(object entity)
+ public virtual ObjectResult Post(object entity)
{
_resourceRepository.Add(entity);
_resourceRepository.SaveChanges();
return new CreatedResult(JsonApiContext.HttpContext.Request.Path, entity);
}
- public ObjectResult Patch(string id, Dictionary entityPatch)
+ public virtual ObjectResult Patch(string id, Dictionary entityPatch)
{
var entity = _resourceRepository.Get(id);
if(entity == null) {
@@ -55,7 +55,7 @@ public ObjectResult Patch(string id, Dictionary entityPatc
return new OkObjectResult(entity);
}
- public ObjectResult Delete(string id)
+ public virtual ObjectResult Delete(string id)
{
_resourceRepository.Delete(id);
_resourceRepository.SaveChanges();
diff --git a/JsonApiDotNetCore/Data/GenericDataAccess.cs b/JsonApiDotNetCore/Data/GenericDataAccess.cs
index ef36114349..d1f8d6c8db 100644
--- a/JsonApiDotNetCore/Data/GenericDataAccess.cs
+++ b/JsonApiDotNetCore/Data/GenericDataAccess.cs
@@ -1,22 +1,60 @@
using System;
-using System.Collections.Generic;
+using System.Reflection;
using System.Linq;
using System.Linq.Expressions;
-using JsonApiDotNetCore.Abstractions;
-using System.Reflection;
using JsonApiDotNetCore.Extensions;
-using JsonApiDotNetCore.Routing;
using Microsoft.EntityFrameworkCore;
-public class GenericDataAccess
+namespace JsonApiDotNetCore.Data
{
- public DbSet GetDbSet(DbContext context) where T : class
+ public class GenericDataAccess
{
- return context.Set();
- }
+ public DbSet GetDbSet(DbContext context) where T : class
+ {
+ return context.Set();
+ }
- public IQueryable IncludeEntity(IQueryable queryable, string includedEntityName) where T : class
- {
- return queryable.Include(includedEntityName);
+ public IQueryable IncludeEntity(IQueryable queryable, string includedEntityName) where T : class
+ {
+ return queryable.Include(includedEntityName);
+ }
+
+ public T SingleOrDefault(object query, string param, object value)
+ {
+ var queryable = (IQueryable) query;
+ var expression = GetEqualityExpressionForProperty(queryable, param, value);
+ return queryable.SingleOrDefault(expression);
+ }
+
+ public IQueryable Where(object query, string param, object value)
+ {
+ var queryable = (IQueryable) query;
+ var expression = GetEqualityExpressionForProperty(queryable, param, value);
+ return queryable.Where(expression);
+ }
+
+ private Expression> GetEqualityExpressionForProperty(IQueryable query, string param, object value)
+ {
+ var currentType = query.ElementType;
+ var property = currentType.GetProperty(param);
+
+ if (property == null)
+ {
+ throw new ArgumentException($"'{param}' is not a valid property of '{currentType}'");
+ }
+
+ // convert the incoming value to the target value type
+ // "1" -> 1
+ var convertedValue = Convert.ChangeType(value, property.PropertyType);
+ // {model}
+ var prm = Expression.Parameter(currentType, "model");
+ // {model.Id}
+ var left = Expression.PropertyOrField(prm, property.Name);
+ // {1}
+ var right = Expression.Constant(convertedValue, property.PropertyType);
+ // {model.Id == 1}
+ var body = Expression.Equal(left, right);
+ return Expression.Lambda>(body, prm);
+ }
}
}
diff --git a/JsonApiDotNetCore/Data/GenericDataAccessAbstraction.cs b/JsonApiDotNetCore/Data/GenericDataAccessAbstraction.cs
new file mode 100644
index 0000000000..eecc29cd5a
--- /dev/null
+++ b/JsonApiDotNetCore/Data/GenericDataAccessAbstraction.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Reflection;
+using System.Linq;
+using System.Linq.Expressions;
+using JsonApiDotNetCore.Extensions;
+using Microsoft.EntityFrameworkCore;
+
+namespace JsonApiDotNetCore.Data
+{
+ public class GenericDataAccessAbstraction
+ {
+ private GenericDataAccess _dataAccessorInstance;
+ private DbContext _dbContext;
+ private Type _modelType;
+ private string _includedRelationship;
+ public GenericDataAccessAbstraction(object dbContext, Type modelType, string includedRelationship)
+ {
+ _dataAccessorInstance = (GenericDataAccess)Activator.CreateInstance(typeof(GenericDataAccess));
+ _dbContext = (DbContext) dbContext;
+ _modelType = modelType;
+ _includedRelationship = includedRelationship?.ToProperCase();
+ }
+
+ public object SingleOrDefault(string propertyName, string value)
+ {
+ var dbSet = GetDbSet();
+ return InvokeGenericDataAccessMethod("SingleOrDefault", new[] { dbSet, propertyName, value });
+ }
+
+ public IQueryable Filter(string propertyName, string value)
+ {
+ var dbSet = GetDbSet();
+ return (IQueryable)InvokeGenericDataAccessMethod("Where", new[] { dbSet, propertyName, value });
+ }
+
+ private object InvokeGenericDataAccessMethod(string methodName, params object[] propertyValues)
+ {
+ var dataAccessorMethod = _dataAccessorInstance.GetType().GetMethod(methodName);
+ var genericDataAccessorMethod = dataAccessorMethod.MakeGenericMethod(_modelType);
+ return genericDataAccessorMethod.Invoke(_dataAccessorInstance, propertyValues);
+ }
+
+ public object GetDbSet()
+ {
+ var dataAccessorGetDbSetMethod = _dataAccessorInstance.GetType().GetMethod("GetDbSet");
+ var genericGetDbSetMethod = dataAccessorGetDbSetMethod.MakeGenericMethod(_modelType);
+ var dbSet = genericGetDbSetMethod.Invoke(_dataAccessorInstance, new [] { _dbContext });
+ if (!string.IsNullOrEmpty(_includedRelationship))
+ {
+ dbSet = IncludeRelationshipInContext(dbSet);
+ }
+ return dbSet;
+ }
+
+ private object IncludeRelationshipInContext(object dbSet)
+ {
+ var includeMethod = _dataAccessorInstance.GetType().GetMethod("IncludeEntity");
+ var genericIncludeMethod = includeMethod.MakeGenericMethod(_modelType);
+ return genericIncludeMethod.Invoke(_dataAccessorInstance, new []{ dbSet, _includedRelationship });
+ }
+
+ }
+}
diff --git a/JsonApiDotNetCore/Data/ResourceRepository.cs b/JsonApiDotNetCore/Data/ResourceRepository.cs
index 51eb628a3c..6b5ed59611 100644
--- a/JsonApiDotNetCore/Data/ResourceRepository.cs
+++ b/JsonApiDotNetCore/Data/ResourceRepository.cs
@@ -1,12 +1,12 @@
using System;
+using System.Reflection;
using System.Collections.Generic;
using System.Linq;
-using System.Linq.Expressions;
using JsonApiDotNetCore.Abstractions;
-using System.Reflection;
using JsonApiDotNetCore.Extensions;
using JsonApiDotNetCore.Routing;
using Microsoft.EntityFrameworkCore;
+using System.Collections;
namespace JsonApiDotNetCore.Data
{
@@ -21,53 +21,48 @@ public ResourceRepository(JsonApiContext context)
public List