C# EF core';s HasIndex(表达式<;Func<;T,对象>;)是否始终正确地获取索引顺序?

C# EF core';s HasIndex(表达式<;Func<;T,对象>;)是否始终正确地获取索引顺序?,c#,ef-core-3.1,C#,Ef Core 3.1,据我所知,没有一种可靠的、有文档记录的方法可以按照匿名类型属性在源文件中声明的顺序获取它们,这让我怀疑我是否使用了EF core的HasIndex,因此: modelBuilder.Entity<T>(entity => entity.HasIndex(e => new { e.Z, e.A }) ) …因为我认为数组元素顺序决定索引列顺序是合乎逻辑的 但是,我很难在没有硬编码字符串的情况下使用此表单,因为DbSet是这样定义的: public virtual DbSe

据我所知,没有一种可靠的、有文档记录的方法可以按照匿名类型属性在源文件中声明的顺序获取它们,这让我怀疑我是否使用了EF core的HasIndex,因此:

modelBuilder.Entity<T>(entity => entity.HasIndex(e => new { e.Z, e.A }) )
…因为我认为数组元素顺序决定索引列顺序是合乎逻辑的

但是,我很难在没有硬编码字符串的情况下使用此表单,因为
DbSet
是这样定义的:

public virtual DbSet<X> X {get;set;}
……这有点


因此,如果能够具体确认“是的,
HasIndex(e=>new{e.Z,e.A})
肯定会将索引创建为Z,A”,那将是了不起的;我会对它进行测试,但我不认为“尝试并观察它在这种情况下是否正确”意味着它保证它将始终有效,而不是“是的,它会有效,因为…”“

是的,
EF
按照您定义的顺序创建索引,这是完全正确的

因为索引中列的顺序在关系数据库中非常重要,所有搜索场景都是按列的顺序搜索索引(在构建执行计划时)

正如您所知,当更改特定索引的列顺序时,您应该基于新顺序为create重建该索引

据我所知,没有一种可靠的、有文档记录的方法可以按照匿名类型属性在源文件中声明的顺序获取它们

您缺少这样一个事实,即在这里,您不是通过反射在运行时处理匿名类型,而是使用编译时生成的表示匿名类型实例化的表达式树。lambda的主体是(从语法上看不是
MemberInit
),它是一个构造函数调用,按照指定的顺序包含定义表达式,并且还映射到专为匿名类型创建的:

Members
属性提供构造函数参数和与这些值对应的类型成员之间的映射。在构造匿名类型的情况下,此属性将构造函数参数映射到匿名类型公开的属性。此映射信息非常重要,因为通过构造匿名类型初始化的字段或访问这些字段的属性无法通过
构造函数
参数
节点的
属性发现

关于订单,文件上说:

如果程序集中的两个或多个匿名对象初始值设定项指定了顺序相同且名称和类型相同的属性序列,则编译器会将这些对象视为相同类型的实例。它们共享相同的编译器生成的类型信息


因此,由于初始化顺序是匿名类型标识的一部分,因此编译器应该保留它,并反过来反映在编译器生成的lambda表达式中。

鉴于EF基于表达式树(而不是它们将创建的.NET对象)生成SQL查询,我希望它也能以同样的方式生成索引定义语句,因此基于表达式树,而不是它们将创建的.NET对象。但这是我的假设,不是基于确凿的事实。根据Saeed的回答,这并不是你需要它,而是
nameof
在那种上下文中不起作用的解决方法是完全限定标识符,从名称空间到属性。无论名称的限定范围有多广,最后一部分都是
nameof
表达式的目标标识符(这让一些询问过如何获得限定名称的人感到失望)。完全限定可能不太好,但它不需要实体的实例。表达式可以按预期的顺序解构。编译器使用相应属性的RuntimeMethodHandle并按顺序传递它们参见本例,注意编译器声明了2个匿名类型,构造函数参数按交换顺序(查看参数名称)因此,
NewExpression
也可以按顺序进行检查现在我承认这并不意味着EF实际上尊重顺序,但考虑到它们很容易做到,我很难想象如果不能保证顺序,它们会提供这样一种方法。如果是这样的话,我希望他们只公开我刚刚通过EF源挖掘的基于字符串的重载。它们不使用NewExpression,而是按照引用顺序查看MemberAccessExpressions(属性)。基本上是一样的。还需要注意的是,表达式是声明代码形状的一种方式,而不是结果。必须维护顺序,无论是用于内省,还是在编译/执行它们时(假设一个属性有副作用,则需要保留顺序)。这是太多的代码挖掘,并试图从我的手机写一个答案。但是下面的答案是正确的,我只是从EF源中找到的。令我惊讶的是,他们根本不使用这个新的表达方式!相反,它们使用MemberAccessExpressions,并按顺序处理它们,如果有人需要,则作为参考cares@pinkfloydx33实际上,他们确实会检查
NewExpression
,否则它根本不起作用。看这里,这就是我没有进一步挖掘/注意太多的原因。我怀疑他们不得不这么做(见OP上的评论),我猜他们是懒惰的,哈哈
public virtual DbSet<X> X {get;set;}
modelBuilder.Entity<SessionChargingProfileLog>(entity =>
{
    var x = new X(0, 0, "");

    entity.HasIndex(nameof(x.Z), nameof(x.A)).IsClustered().IncludeProperties(nameof(x.B));

});