Broadcast me completely







Have you ever worked with Entity Framework or other ORM and got it NotSupportedException



? Many people have received :







InvalidOperationException: Error generated for warning 'Microsoft.EntityFrameworkCore.Query.QueryClientEvaluationWarning: The LINQ expression could not be translated and will be evaluated locally.'
      
      





Mark Seaman strongly believes that, with one exception, all existing implementations violate LSP . He is even willing to send a free copy of his book to the first reader to point him to a real, public implementation IQueryable<T>



that can accept any expression and not throw an exception. For nine years, the book has not found its owner :)







  • Hi Mark,

    I am writing a blog post that refers to your artticle. I am wondering if you have ever sent a free copy of your book to someone. Presumably not:)
  • Hi Maxim

    That’s right: I haven’t.

    Regards

    Mark Seemann


. , ToListAsync



. ORM. , IQueryable<T>



API
? , — «».







ToListAsync



ToListAsync



. . IQueryable<TSource>



IAsyncEnumerable<TSource>



AsAsyncEnumerable



:







public static async Task<List<TSource>> ToListAsync<TSource>(
   [NotNull] this IQueryable<TSource> source,
   CancellationToken cancellationToken = default)
{
   var list = new List<TSource>();
   await foreach (var element in source.AsAsyncEnumerable().WithCancellation(cancellationToken))
   {
       list.Add(element);
   }

   return list;
}
      
      





, , , :







public static IAsyncEnumerable<TSource> AsAsyncEnumerable<TSource>(
   [NotNull] this IQueryable<TSource> source)
{
   Check.NotNull(source, nameof(source));

   if (source is IAsyncEnumerable<TSource> asyncEnumerable)
   {
       return asyncEnumerable;
   }

   throw new InvalidOperationException(CoreStrings.IQueryableNotAsync(typeof(TSource)));
}
      
      





- . , ToListAsync



Task.FromResult



, .







IQueryable



public API?



IQueryable



Entity Framework / NHibernate / Linq2Db . ORM. ORM — .







Linq2Db Entity Framework , , .

, , . « API»?







Out Of Process



, IQueryable



. GraphQl OData. , , . , rest-like API , . Query Objects



.







In process



IQueryable



, , , , . , , . à la DataQueryHandler



CQRS/Vertical Slices. IQueryable



, .







IQueryable





, IQueryable



. , . :







public enum UserType: byte
{
   Regular,
   Vip
}

public class User : IdentityUser
{
   [NotMapped]
   public int Age { get; set; }

   public Organization Organization { get; set; }

   public UserType UserType { get; set; }

   public string FirstName { get; set; }

   public string LastName { get; set; }

   public string FullName => $"{FirstName} {LastName}";
}
      
      







— , :







public static class Demo
{
   public static bool Filter(User user) =>    
       user.FirstName.StartsWith("");

   // 
   public static object Works(IEnumerable<User> users) =>
       users
           .Where(x => Filter(x))
           .ToList();  

   //  
   public static object ThrowsException(IQueryable<User> users) =>
       users
           .Where(x => Filter(x))
           .ToList();

   //  ,  
   public static object WorksAgain(IQueryable<User> users) =>
       users
           .Where(x => x.FirstName.StartsWith(""))
           .ToList();
}
      
      





, « ( )» LINQ- , — , visitor, . .

, Q&A DotNext Moscow 2020, BCL. , . , ORM «» . SQL Filter



? — « ». .







Entity Framework, . :







public static class DbFunctions
{
   public static bool Filter(User user) =>    
       user.FirstName.StartsWith(""); 
}

//...
       users
           .Where(DbFunctions.Filter)
           .ToList();

      
      





,



public static object Exception (IQueryable<User> users) =>
   users
       .Where(x => x.FirstName.StartsWith(""))
       .ToList();
      
      





StartsWith



Contains



, SQL : LIKE “%”



LIKE “%%”



, . , BCL . , :







// 
public static object EnumException (IQueryable<User> users) =>
   users
       .Select(x => x.UserType.ToString())
       .Distinct()
       .ToList();

//   
public static object EnumWorks (IQueryable<User> users) =>
   users
       .Select(x => ((byte)x.UserType).ToString())
       .Distinct()
       .ToList();
      
      





, Underlying Type Enum



ToString



Convert



.







, MethodCallExpression



, — . , () ( Expression.Convert) , . , DLR, runtime. , , ORM , .




IQueryable



``IQueryable```? . ORM , .. :







select tmp.* from (select from * table) as tmp
      
      





: IQueryable



DbContext



. , Task.WhenAll



, IQueryable



, IQueryable



, .









. , « Query Provider ». , :







FullName => FirstName + " " + LastName
      
      





,







FullName => $"{FirstName} {LastName}"
      
      





[NotMapped]



. , :







public static object NotMappedException (IQueryable<User> users) =>
   users
       .Where(x => x.Age > 18)
       .ToList();
      
      





, , , IQueryable



, , , .









, . EF Core ( EF 6, , ):







public static object ConstructorWorks (IQueryable<User> users) =>
   users
       .Select(x => x.FullName)
       .ToList();
      
      





:







public static object ConstructorException (IQueryable<User> users) =>
   users
       .Where(x => x.FullName.StartsWith(""))   
       .Select(x => x.FullName)
       .ToList();
      
      





«» EF Core. Select , x => x.FullName



. «» , :







public static object OrganizationWorksOrNot (IQueryable<User> users) =>
   users
       .Select(x => new { x.Organization.FullName })
       //.Where(x => x.FullName.StartsWith("")) 
       .ToList();
      
      





, , . , - Select



. Lazy Loading Include



.







Include



Select



— , , change tracker ( ). , Include



Lazy Loading « In Defense of Lazy Loading», - DDD-.




Use IQueryable



in internal APIs is okay, but it comes with surprises. What is more: pros or cons - everyone decides for himself. Share in the comments your experience of exciting untranslated query debugging. Let's add interesting stories to the article to make life a little easier for C # programmers.








All Articles