Méthode LINQ TO SQL Replace

c# expression-trees linq linq-to-sql

Question

J'ai du code, ça marche bien.

 using (var dbContext = new UnitOfWorkFactory(sqlConnection).Create())
 {
        var result = dbContext.Repository<SomeTable>()
            .Get()
            .AsNoTracking()
            .Where(r => r.Id == 1)
            .Select(item => new
            {
                TableId = item.TableId,
                OriginalTableName = item.TableName.Replace("$", "_")
            })
            .SingleOrDefault(); 

Lorsque j'essaie de remplacer la logique par une méthode privée distincte, une exception se produit. Je comprends que la raison principale est que le fournisseur LINQ to SQL ne peut pas traduire la méthode clr en SQL.

...
.Select(item => new
 {
   TableId = item.TableId,
   OriginalTableName = SubQueryReplace(item.TableName)
 })
...

En fait, je suppose que je dois utiliser l'arbre d'expression, mais je ne peux pas résoudre comment je dois l'écrire. Lorsque j'essaie de renvoyer Expression<Func<string>> depuis la méthode SubQueryReplace, le compilateur CLR est malheureux, mais lorsque j'essaie de faire

private Expression<Func<string, string>>SubQueryReplace(string fieldValue)
{
   Expression<Func<string, string>> exp = (tableName) => tableName.Replace("D", "_");`
   return exp
}

...
.Select(item => new
 {
   TableId = item.TableId,
   OriginalTableName = SubQueryReplace.Compile.Invoke(item.TableName)
 })
...

LINQ to Sql ne comprend pas ce que je veux en tirer.

Donc, comme vous pouvez le voir, je suis confus. S'il vous plaît aider à résoudre cette tâche syntaxique.

Réponse acceptée

Utilisez LinqKit et écrivez:

...
.AsExpandable()
.Select(item => new
 {
   TableId = item.TableId,
   OriginalTableName = SubQueryReplace(item.TableName).Expand()
 })
...

Réponse populaire

Ai-je raison de dire que votre problème est qu'un IQueryable ne peut utiliser aucune fonction locale et ne peut pas traduire toutes les méthodes LINQ standard en SQL comme décrit dans les méthodes LINQ prises en charge et non prises en charge ?

J'irais pour AsEnumerable . AsEnumerable amènera l'entrée dans la mémoire locale afin que vous puissiez appeler n'importe quelle fonction locale de votre choix.

Comme il semble que le résultat de votre requête ne devrait comporter qu'un seul élément, le transport du nom de table complet dans la mémoire locale avant de le convertir en un nom OriginalTableName ne pose aucun problème.

var result = dbContext.Repository<SomeTable>()
    ...
    .Where(someTableElement => someTableElement.Id == 1)
    .Select(tableItem => new
    {
        TableId = tableItem.TableId,
        TableName = tableIem.TableName,
    })
    .AsEnumerable()

    // from here, all elements (expected to be only one) are in local memory
    // so you can call:
    .Select(localItem => new
    {
        TableId = localItem.TableId,
        OriginalTableName = localItem.TableName.Replace("$", "_")
    })
    .SingleOrDefault(); 

Soyez prudent lorsque vous utilisez AsEnumerable . Essayez de ne pas transporter beaucoup de données dans la mémoire locale que vous n'utiliserez pas. Essayez donc d’exécuter Join / Where / Select autant que possible en tant que AsQueryable. Si vous avez limité vos données à ce que vous comptez vraiment utiliser, déplacez-les dans la mémoire locale.




Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi