The differences between IEnumerable and IQueryable, as well as the ExpressionTree Expression Tree and cronexpression expression
For the difference between IEnumerable and IQueryable, we need to start with the generic commissioned Func <T>. Let's look at a simple example of generic delegation:
class Program
{
static void Main(string[] args)
{
Func<int, bool> f = i => i > 5;
Console.WriteLine(f(3));
Console.WriteLine(f(10));
Console.ReadKey();
}
}
Func <T> is "syntactic sugar". In fact, the compiler will generate a temporary method internally and then execute this method. It is equivalent to the following:
class Program
{
static void Main(string[] args)
{
Func<int, bool> f = DoSth;
Console.WriteLine(f(3));
Console.ReadKey();
}
static bool DoSth(int i)
{
return i > 5;
}
}
Above, the path for. NET internal operation is: compile C # code → compile the compiler into the intermediate language IL → execute the JIT compilation cost locally during the runtime
■ Use Expression Tree
However, what should we do if we want to execute code at runtime?
. NET provides Expression Tree for us to execute code at runtime.
For example, the above Func <int, bool> f = I => I> 5; Expression Tree understands this Expression as follows:
○ F is Expression <Func <int, bool> type, level Expression <TDelegate> type
○ => Understood as the BinaryExpression type
○ => I on the left and right sides is interpreted as ParameterExpression.
○ => The 5 on the right is interpreted as ConstantExpression.
Therefore, if we use Expression Tree to execute code at runtime, we can write as follows:
class Program
{
static void Main(string[] args)
{
//Func<int, bool> f = i => i > 5;
ParameterExpression iParam = Expression.Parameter(typeof (int), "i");
ConstantExpression constExp = Expression.Constant(5, typeof (int));
BinaryExpression greaterThan = Expression.GreaterThan(iParam, constExp);
Expression<Func<int, bool>> f = Expression.Lambda<Func<int, bool>>(greaterThan, iParam);
Func<int, bool> myDele = f.Compile();
Console.WriteLine(myDele(3));
Console.WriteLine(myDele(10));
Console.ReadKey();
}
}
■ Differences between IQueryable and IEnumerable
Now, let's look at an example of IEnumerable:
class Program
{
static void Main(string[] args)
{
int[] intArr = new[] {1, 2, 3, 6, 8};
IEnumerable<int> result = Enumerable.Where(intArr, i => i > 5);
foreach (var item in result)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
}
Let's take a look at Enumerable, which implements the IEnumerable interface. Its definition is as follows:
Let's take a look at Queryable, which implements the IQueryable interface. Its definition is as follows:
It is found that many methods of Enumerable and Queryable have the same names, but the types of parameters received by parameters are different. The type of parameters received by Enumerable is to delegate Func <TDelegate>, the parameter type received by Querable is Expression <Func <TDelegate>, Which is Expression Tree and Expression Tree.
Therefore, the expression for IEnumerable <T> is determined during the compilation period, and the expression for IQueryable <T> is determined at runtime.
■ Understand IQueryable in the Entity Framework application instance <T>
First, apply the Entity Framework component in the console application.
Create context classes, classes, and initial data for Entity Framework:
public class Person
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
public class MyContext : DbContext
{
public MyContext() : base("myConn")
{
Database.SetInitializer(new DbInirializer());
}
public DbSet<Person> People { get; set; }
}
public class DbInirializer : CreateDatabaseIfNotExists<MyContext>
{
protected override void Seed(MyContext context)
{
IList<Person> people = new List<Person>();
People. Add (new Person () {Name = "Zhang San", Age = 21 });
People. Add (new Person () {Name = "", Age = 22 });
People. Add (new Person () {Name = "Zhao Wu", Age = 23 });
foreach (var item in people)
{
context.People.Add(item);
}
base.Seed(context);
}
}
If we go to the definition of DbSet, we can see that DbSet implements the IQueryable interface.
Configure the connection string.
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<connectionStrings>
<add name="myConn"
connectionString="Data Source=.;User=yourusename;Password=yourpassword;Initial Catalog=MyTest;Integrated Security=True"
providerName="System.Data.SqlClient"/>
</connectionStrings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
</configuration>
In the main program:
class Program
{
static void Main(string[] args)
{
using (var context = new MyContext())
{
foreach (var item in context.People)
{
Console.WriteLine(item.Name);
}
}
Console.ReadKey();
}
}
Now let's take a look at some of the features of IQueryable <T>.
We know that DbSet implements the IQuerayble interface, so the People attribute type of the context is IQueryable <Person>.
Pass,
IQueryable <Person> people = context. People;
The resulting people is an expression and an SQL statement. Now we try to print the people expression in different situations.
class Program
{
static void Main(string[] args)
{
using (var context = new MyContext())
{
IQueryable<Person> people = context.People;
var r = new Random();
Func<bool> rBool = () => r.Next()%2 == 0;
Console.WriteLine(people);
if (rBool())
{
people = people.Where(p => p.Age > 21);
Console.WriteLine(people);
}
else
{
people = people.OrderBy(p => p.Age);
Console.WriteLine(people);
}
}
Console.ReadKey();
}
}
From this we can see that IQueryable presents an expression rather than a set. Through this expression, we can load data that meets the conditions as needed.