Ho un progetto in cui il front-end JavaScript specifica un elenco di colonne da ordinare.Come ordinare dinamicamente da determinate proprietà dell'entità in EntityFramework 7 (Core)
Quindi nel back-end ho un'applicazione multistrato. scenario tipico
- livello di servizio (i modelli di servizio (DTO) proprietà corrispondono qualunque sia il lato client vuole ordinare da)
- strato Domain (espone interfacce repository per accedere agli oggetti persistenti) strato
- ORM (implementa il repository e utilizza Entity Framework 7 (aka Entity Framework core) per accedere a un database di SQL Server)
prega di notare che System.Linq.Dynamic non è supportata per DNX Nucleo v5.0 o. NET Platform v5.4 quindi non posso usare quella biblioteca
Ho la seguente applicazione nel mio repository cose:
public async Task<IEnumerable<Thing>> GetThingsAsync(IEnumerable<SortModel> sortModels)
{
var query = GetThingsQueryable(sortModels);
var things = await query.ToListAsync();
return things;
}
private IQueryable<Thing> GetThingsQueryable(IEnumerable<SortModel> sortModels)
{
var thingsQuery = _context.Things
.Include(t => t.Other)
.Where(t => t.Deleted == false);
// this is the problematic area as it does not return a valid queyable
string orderBySqlStatement = GetOrderBySqlStatement(sortModels);
thingsQuery = thingsQuery.FromSql(orderBySqlStatement);
return thingsQuery ;
}
/// this returns something like " order by thingy1 asc, thingy2 desc"
private string GetOrderBySqlStatement(IEnumerable<SortModel> sortModels)
{
IEnumerable<string> orderByParams = sortModels.Select(pair => { return pair.PairAsSqlExpression; });
string orderByParamsConcat = string.Join(", ", orderByParams);
string sqlStatement = orderByParamsConcat.Length > 1 ? $" order by {orderByParamsConcat}" : string.Empty;
return sqlStatement;
}
e questo è l'oggetto che contiene un nome di colonna e un ordine dalla direzione (crescente o decrescente)
public class SortModel
{
public string ColId { get; set; }
public string Sort { get; set; }
public string PairAsSqlExpression
{
get
{
return $"{ColId} {Sort}";
}
}
}
Questo approccio tenta di combinare un'istruzione SQL con qualsiasi entità creata per l'interrogazione precedente. Ma ottengo un:
Microsoft.Data.Entity.Query.Internal.SqlServerQueryCompilationContextFactory:Verbose: Compiling query model: 'from Thing t in {value(Microsoft.Data.Entity.Query.Internal.EntityQueryable`1[MyTestProj.Data.Models.Thing]) => AnnotateQuery(Include([t].DeparturePort)) => AnnotateQuery(Include([t].ArrivalPort)) => AnnotateQuery(Include([t].Consignments))} where (([t].CreatorBusinessId == __businessId_0) AndAlso (Convert([t].Direction) == __p_1)) select [t] => AnnotateQuery(QueryAnnotation(FromSql(value(Microsoft.Data.Entity.Query.Internal.EntityQueryable`1[MyTestProj.Data.Models.Thing]), " order by arrivalDate asc, arrivalPortCode asc", []))) => Count()'
Microsoft.Data.Entity.Query.Internal.SqlServerQueryCompilationContextFactory:Verbose: Optimized query model: 'from Thing t in value(Microsoft.Data.Entity.Query.Internal.EntityQueryable`1[MyTestProj.Data.Models.Thing]) where (([t].CreatorBusinessId == __businessId_0) AndAlso (Convert([t].Direction) == __p_1)) select [t] => Count()'
Microsoft.Data.Entity.Query.Internal.QueryCompiler:Error: An exception occurred in the database while iterating the results of a query.
System.InvalidOperationException: The Include operation is not supported when calling a stored procedure.
at Microsoft.Data.Entity.Query.ExpressionVisitors.RelationalEntityQueryableExpressionVisitor.VisitEntityQueryable(Type elementType)
at Microsoft.Data.Entity.Query.ExpressionVisitors.EntityQueryableExpressionVisitor.VisitConstant(ConstantExpression constantExpression)
at System.Linq.Expressions.ConstantExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.Data.Entity.Query.ExpressionVisitors.ExpressionVisitorBase.Visit(Expression expression)
at Microsoft.Data.Entity.Query.EntityQueryModelVisitor.ReplaceClauseReferences(Expression expression, IQuerySource querySource, Boolean inProjection)
at Microsoft.Data.Entity.Query.EntityQueryModelVisitor.CompileMainFromClauseExpression(MainFromClause mainFromClause, QueryModel queryModel)
at Microsoft.Data.Entity.Query.RelationalQueryModelVisitor.CompileMainFromClauseExpression(MainFromClause mainFromClause, QueryModel queryModel)
at Microsoft.Data.Entity.Query.EntityQueryModelVisitor.VisitMainFromClause(MainFromClause fromClause, QueryModel queryModel)
at Remotion.Linq.Clauses.MainFromClause.Accept(IQueryModelVisitor visitor, QueryModel queryModel)
at Remotion.Linq.QueryModelVisitorBase.VisitQueryModel(QueryModel queryModel)
at Microsoft.Data.Entity.Query.EntityQueryModelVisitor.VisitQueryModel(QueryModel queryModel)
at Microsoft.Data.Entity.Query.RelationalQueryModelVisitor.VisitQueryModel(QueryModel queryModel)
at Microsoft.Data.Entity.Query.Internal.SqlServerQueryModelVisitor.VisitQueryModel(QueryModel queryModel)
at Microsoft.Data.Entity.Query.EntityQueryModelVisitor.CreateAsyncQueryExecutor[TResult](QueryModel queryModel)
at Microsoft.Data.Entity.Storage.Database.CompileAsyncQuery[TResult](QueryModel queryModel)
at Microsoft.Data.Entity.Query.Internal.QueryCompiler.<>c__DisplayClass19_0`1.<CompileAsyncQuery>b__0()
at Microsoft.Data.Entity.Query.Internal.CompiledQueryCache.GetOrAddAsyncQuery[TResult](Object cacheKey, Func`1 compiler)
at Microsoft.Data.Entity.Query.Internal.QueryCompiler.CompileAsyncQuery[TResult](Expression query)
at Microsoft.Data.Entity.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
Exception thrown: 'System.InvalidOperationException' in EntityFramework.Core.dll
Exception thrown: 'System.InvalidOperationException' in mscorlib.ni.dll
Exception thrown: 'System.InvalidOperationException' in mscorlib.ni.dll
Microsoft.AspNet.Diagnostics.Entity.DatabaseErrorPageMiddleware:Verbose: System.InvalidOperationException occurred, checking if Entity Framework recorded this exception as resulting from a failed database operation.
Microsoft.AspNet.Diagnostics.Entity.DatabaseErrorPageMiddleware:Verbose: Entity Framework recorded that the current exception was due to a failed database operation. Attempting to show database error page.
Microsoft.Data.Entity.Storage.Internal.SqlServerConnection:Verbose: Opening connection 'Server=(localdb)\mssqllocaldb;Database=SpeediCargo;Trusted_Connection=True;MultipleActiveResultSets=true'.
Microsoft.Data.Entity.Storage.Internal.SqlServerConnection:Verbose: Closing connection 'Server=(localdb)\mssqllocaldb;Database=SpeediCargo;Trusted_Connection=True;MultipleActiveResultSets=true'.
Microsoft.Data.Entity.Storage.Internal.SqlServerConnection:Verbose: Opening connection 'Server=(localdb)\mssqllocaldb;Database=SpeediCargo;Trusted_Connection=True;MultipleActiveResultSets=true'.
Microsoft.Data.Entity.Storage.Internal.SqlServerConnection:Verbose: Closing connection 'Server=(localdb)\mssqllocaldb;Database=SpeediCargo;Trusted_Connection=True;MultipleActiveResultSets=true'.
Microsoft.Data.Entity.Storage.Internal.SqlServerConnection:Verbose: Opening connection 'Server=(localdb)\mssqllocaldb;Database=SpeediCargo;Trusted_Connection=True;MultipleActiveResultSets=true'.
Microsoft.Data.Entity.Storage.Internal.RelationalCommandBuilderFactory:Information: Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT OBJECT_ID(N'__EFMigrationsHistory');
Microsoft.Data.Entity.Storage.Internal.SqlServerConnection:Verbose: Closing connection 'Server=(localdb)\mssqllocaldb;Database=SpeediCargo;Trusted_Connection=True;MultipleActiveResultSets=true'.
Microsoft.Data.Entity.Storage.Internal.SqlServerConnection:Verbose: Opening connection 'Server=(localdb)\mssqllocaldb;Database=SpeediCargo;Trusted_Connection=True;MultipleActiveResultSets=true'.
Microsoft.Data.Entity.Storage.Internal.RelationalCommandBuilderFactory:Information: Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
Sembra che non sia possibile combinare SQL per l'ordine per parte con il resto della query di linq? Oppure il problema è che non sto anteponendo le colonne con [t] e Entity non è in grado di capire quali sono quelle colonne?
In ogni caso, c'è qualche esempio o raccomandazione su come ottenere ciò che voglio con Entity 7 e con il framework core .net?
Spero che una parte della domanda sta verificando qualcosa di simile a 'GetThingsQueryable (nuova Lista() {new SortModel() {ColId = "A", Sort = "; DROP TABLE Studenti"}) ' –
Sono d'accordo Eric, dovrei essere consapevole delle iniezioni SQL – iberodev
Penso che' FromSql' si aspetta un'istruzione SQL completa. E non "mescola" con il precedente. –