有趣的 Linq to SQL 公共基类行为

发布于 2024-12-08 04:20:44 字数 27014 浏览 1 评论 0原文

这是一个关于 InvalidOperationException 的问题,消息为 Class member X is unmapped。

我们的系统之一对于具有框架版本的每个 LinqToSql 实体具有相同的基本实体 3.5.

我遇到了一个非常奇怪的问题,我开始对此进行研究。我做了一个非常小的项目,以便能够更轻松地定位问题。

实体基类

public abstract class EntityBase
{
    public virtual long ID { get; set; }
}

DataContext 和实体

[Database(Name = "TestDatabase")]
public class EntitiesDataContext : DataContext
{
    public EntitiesDataContext() :
        base(Settings.Default.TestDatabaseConnectionString, new AttributeMappingSource())
    {
    }
}

[Table(Name = "dbo.MyEntity")]
public class MyEntity : EntityBase
{
    private long _EntityID;

    [Column(Name = "EntityID", Storage = "_EntityID")]
    public override long ID
    {
        get { return _EntityID; }
        set { _EntityID = value; }
    }

    [Column] public string Title;
}

问题在于重写的ID。我对不同的映射属性/属性名称设置做了很多变化,但问题似乎不在于命名,而在于基类。而且.NET3.5和.NET4.0之间也有区别。

因此,对于以下陈述,请想象一下

using (var ctx = new EntitiesDataContext())
{
    //statement
}

而 GetTable() 是 GetTable()。

失败表示类成员 EntityBase.ID 未映射。异常。 有效是指预期的行为。

1(在 3.5 中) 作品:

var result = ctx.GetTable().Where(i => i.ID == 2).FirstOrDefault();

2(在 3.5 中)失败

var result = ctx.GetTable().FirstOrDefault(i => i.ID == 2);

3(在 3.5 中) 作品:

var result = ctx.GetTable().FirstOrDefault(i => i.ID.Equals(2));

4(在 3.5 中) 作品:

var result = ctx.GetTable().Where(i => true).FirstOrDefault(i => i.ID == 2);

5(在 3.5 中) 作品:

var result = ctx.GetTable().Where(i => i.ID == 2).FirstOrDefault();

6(在 4.0 中)失败:

var result = ctx.GetTable().Where(i => i.ID == 2).FirstOrDefault()

7(4.0 中) 成功:

var result = ctx.GetTable().Where(i => i.ID.Equals(2)).FirstOrDefault();

8(4.0 中) 失败(与6冗余)

var result = ctx.GetTable().FirstOrDefault(i => i.ID == 2);

9(在4.0中)有效:

var result = ctx.GetTable().FirstOrDefault(i => i.ID.Equals(2));

10(在4.0中)有效:

ctx.GetTable().Where(i => true).FirstOrDefault(i => i.ID == 2);

所以 我无法弄清楚为什么它会失败。 为什么这会起作用

var result = ctx.GetTable().Where(i => true).FirstOrDefault(i => i.ID == 2);

特别是,如果带有谓词的 FirstOrDefault 不起作用, ?以及为什么 Equals 有效而 == 无效。

我一直在寻找一些 Equals 和 == 差异描述,但它没有给我Where(i => true)... 的答案。

看起来这与查询无关,而是与对象初始化有关。因为:

在 4.0 中有效:

var result = ctx.GetTable().Where(i => i.ID == 2).Select(i => i.Title).FirstOrDefault();

但是 :)

在 4.0 中它也有效:

var result = ctx.GetTable().FirstOrDefault();

所以也许不是对象初始化

LinqToSql 构建的 SQL 对于 == 和 Equals 相同。同样,对于

Where(i => true).FirstOrDefault(i => i.ID == 2)

and ,

FirstOrDefault(i => i.ID == 2)

在 FirstOrDefault 之前没有 SQL 查询,并且它按照预期正确构建了查询。 Where(i => true) 只是继续 SQL 查询中包含的表达式构建和 FirstOrDefault 谓词。

我在MSIL中寻找Reflector中的其他原因,但没有发现什么特别的。

有什么猜测吗? :)

谢谢

####Continuation (in .NET4.0)

我设置了 5 个简单的方法来轻松检查 reflector

public void WithEquals(EntitiesDataContext ctx)
{
    ctx.GetTable<MyEntity>().FirstOrDefault(i => i.ID.Equals(2));
}

public void WithFakeWhereAndOperator(EntitiesDataContext ctx)
{
    ctx.GetTable<MyEntity>().Where(i => true).FirstOrDefault(i => i.ID == 2);
}

public void WithOperator(EntitiesDataContext ctx)
{
    ctx.GetTable<MyEntity>().FirstOrDefault(i => i.ID == 2);
}

public void WithOperatorSelect(EntitiesDataContext ctx)
{
    ctx.GetTable<MyEntity>().Where(i => i.ID == 2).Select(i => i).FirstOrDefault();
}

public void WithOperatorAndWhere(EntitiesDataContext ctx)
{
    ctx.GetTable<MyEntity>().Where(i => i.ID == 2).FirstOrDefault();
}

WithOperator 和 WithOperatorAndWhere 失败,但这里是MSIL 和我所看到的:

WithOperator

  .method public hidebysig instance void WithOperator(class LinqToSqlTest.EntitiesDataContext ctx) cil managed
    {
        .maxstack 5
        .locals init (
            [0] class [System.Core]System.Linq.Expressions.ParameterExpression CS$0$0000,
            [1] class [System.Core]System.Linq.Expressions.ParameterExpression[] CS$0$0001)
        L_0000: nop 
        L_0001: ldarg.1 
        L_0002: callvirt instance class [System.Data.Linq]System.Data.Linq.Table`1<!!0> [System.Data.Linq]System.Data.Linq.DataContext::GetTable<class LinqToSqlTest.MyEntity>()
        L_0007: ldtoken LinqToSqlTest.MyEntity
        L_000c: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
        L_0011: ldstr "i"
        L_0016: call class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Parameter(class [mscorlib]System.Type, string)
        L_001b: stloc.0 
        L_001c: ldloc.0 
        L_001d: ldtoken instance int64 LinqToSqlTest.EntityBase::get_ID()
        L_0022: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
        L_0027: castclass [mscorlib]System.Reflection.MethodInfo
        L_002c: call class [System.Core]System.Linq.Expressions.MemberExpression [System.Core]System.Linq.Expressions.Expression::Property(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Reflection.MethodInfo)
        L_0031: ldc.i4.2 
        L_0032: conv.i8 
        L_0033: box int64
        L_0038: ldtoken int64
        L_003d: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
        L_0042: call class [System.Core]System.Linq.Expressions.ConstantExpression [System.Core]System.Linq.Expressions.Expression::Constant(object, class [mscorlib]System.Type)
        L_0047: call class [System.Core]System.Linq.Expressions.BinaryExpression [System.Core]System.Linq.Expressions.Expression::Equal(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.Expression)
        L_004c: ldc.i4.1 
        L_004d: newarr [System.Core]System.Linq.Expressions.ParameterExpression
        L_0052: stloc.1 
        L_0053: ldloc.1 
        L_0054: ldc.i4.0 
        L_0055: ldloc.0 
        L_0056: stelem.ref 
        L_0057: ldloc.1 
        L_0058: call class [System.Core]System.Linq.Expressions.Expression`1<!!0> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Func`2<class LinqToSqlTest.MyEntity, bool>>(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.ParameterExpression[])
        L_005d: call !!0 [System.Core]System.Linq.Queryable::FirstOrDefault<class LinqToSqlTest.MyEntity>(class [System.Core]System.Linq.IQueryable`1<!!0>, class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Func`2<!!0, bool>>)
        L_0062: pop 
        L_0063: ret 
    }

WithFakeWhereAndOperator

 .method public hidebysig instance void WithFakeWhereAndOperator(class LinqToSqlTest.EntitiesDataContext ctx) cil managed
    {
        .maxstack 5
        .locals init (
            [0] class [System.Core]System.Linq.Expressions.ParameterExpression CS$0$0000,
            [1] class [System.Core]System.Linq.Expressions.ParameterExpression[] CS$0$0001)
        L_0000: nop 
        L_0001: ldarg.1 
        L_0002: callvirt instance class [System.Data.Linq]System.Data.Linq.Table`1<!!0> [System.Data.Linq]System.Data.Linq.DataContext::GetTable<class LinqToSqlTest.MyEntity>()
        L_0007: ldtoken LinqToSqlTest.MyEntity
        L_000c: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
        L_0011: ldstr "i"
        L_0016: call class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Parameter(class [mscorlib]System.Type, string)
        L_001b: stloc.0 
        L_001c: ldc.i4.1 
        L_001d: box bool
        L_0022: ldtoken bool
        L_0027: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
        L_002c: call class [System.Core]System.Linq.Expressions.ConstantExpression [System.Core]System.Linq.Expressions.Expression::Constant(object, class [mscorlib]System.Type)
        L_0031: ldc.i4.1 
        L_0032: newarr [System.Core]System.Linq.Expressions.ParameterExpression
        L_0037: stloc.1 
        L_0038: ldloc.1 
        L_0039: ldc.i4.0 
        L_003a: ldloc.0 
        L_003b: stelem.ref 
        L_003c: ldloc.1 
        L_003d: call class [System.Core]System.Linq.Expressions.Expression`1<!!0> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Func`2<class LinqToSqlTest.MyEntity, bool>>(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.ParameterExpression[])
        L_0042: call class [System.Core]System.Linq.IQueryable`1<!!0> [System.Core]System.Linq.Queryable::Where<class LinqToSqlTest.MyEntity>(class [System.Core]System.Linq.IQueryable`1<!!0>, class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Func`2<!!0, bool>>)
        L_0047: ldtoken LinqToSqlTest.MyEntity
        L_004c: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
        L_0051: ldstr "i"
        L_0056: call class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Parameter(class [mscorlib]System.Type, string)
        L_005b: stloc.0 
        L_005c: ldloc.0 
        L_005d: ldtoken instance int64 LinqToSqlTest.EntityBase::get_ID()
        L_0062: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
        L_0067: castclass [mscorlib]System.Reflection.MethodInfo
        L_006c: call class [System.Core]System.Linq.Expressions.MemberExpression [System.Core]System.Linq.Expressions.Expression::Property(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Reflection.MethodInfo)
        L_0071: ldc.i4.2 
        L_0072: conv.i8 
        L_0073: box int64
        L_0078: ldtoken int64
        L_007d: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
        L_0082: call class [System.Core]System.Linq.Expressions.ConstantExpression [System.Core]System.Linq.Expressions.Expression::Constant(object, class [mscorlib]System.Type)
        L_0087: call class [System.Core]System.Linq.Expressions.BinaryExpression [System.Core]System.Linq.Expressions.Expression::Equal(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.Expression)
        L_008c: ldc.i4.1 
        L_008d: newarr [System.Core]System.Linq.Expressions.ParameterExpression
        L_0092: stloc.1 
        L_0093: ldloc.1 
        L_0094: ldc.i4.0 
        L_0095: ldloc.0 
        L_0096: stelem.ref 
        L_0097: ldloc.1 
        L_0098: call class [System.Core]System.Linq.Expressions.Expression`1<!!0> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Func`2<class LinqToSqlTest.MyEntity, bool>>(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.ParameterExpression[])
        L_009d: call !!0 [System.Core]System.Linq.Queryable::FirstOrDefault<class LinqToSqlTest.MyEntity>(class [System.Core]System.Linq.IQueryable`1<!!0>, class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Func`2<!!0, bool>>)
        L_00a2: pop 
        L_00a3: ret 
    }

正如我所见, FirstOrDefault 之间没有区别调用时,WithFakeWhereAndOperator 仅“包含”有关Where 语句的几行:

WithFakeWhereAndOperator 和 WithOperator 差异

WithEquals

.method public hidebysig instance void WithEquals(class LinqToSqlTest.EntitiesDataContext ctx) cil managed
    {
        .maxstack 7
        .locals init (
            [0] class [System.Core]System.Linq.Expressions.ParameterExpression CS$0$0000,
            [1] class [System.Core]System.Linq.Expressions.Expression[] CS$0$0001,
            [2] class [System.Core]System.Linq.Expressions.ParameterExpression[] CS$0$0002)
        L_0000: nop 
        L_0001: ldarg.1 
        L_0002: callvirt instance class [System.Data.Linq]System.Data.Linq.Table`1<!!0> [System.Data.Linq]System.Data.Linq.DataContext::GetTable<class LinqToSqlTest.MyEntity>()
        L_0007: ldtoken LinqToSqlTest.MyEntity
        L_000c: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
        L_0011: ldstr "i"
        L_0016: call class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Parameter(class [mscorlib]System.Type, string)
        L_001b: stloc.0 
        L_001c: ldloc.0 
        L_001d: ldtoken instance int64 LinqToSqlTest.EntityBase::get_ID()
        L_0022: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
        L_0027: castclass [mscorlib]System.Reflection.MethodInfo
        L_002c: call class [System.Core]System.Linq.Expressions.MemberExpression [System.Core]System.Linq.Expressions.Expression::Property(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Reflection.MethodInfo)
        L_0031: ldtoken instance bool [mscorlib]System.Int64::Equals(int64)
        L_0036: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
        L_003b: castclass [mscorlib]System.Reflection.MethodInfo
        L_0040: ldc.i4.1 
        L_0041: newarr [System.Core]System.Linq.Expressions.Expression
        L_0046: stloc.1 
        L_0047: ldloc.1 
        L_0048: ldc.i4.0 
        L_0049: ldc.i4.2 
        L_004a: conv.i8 
        L_004b: box int64
        L_0050: ldtoken int64
        L_0055: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
        L_005a: call class [System.Core]System.Linq.Expressions.ConstantExpression [System.Core]System.Linq.Expressions.Expression::Constant(object, class [mscorlib]System.Type)
        L_005f: stelem.ref 
        L_0060: ldloc.1 
        L_0061: call class [System.Core]System.Linq.Expressions.MethodCallExpression [System.Core]System.Linq.Expressions.Expression::Call(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Reflection.MethodInfo, class [System.Core]System.Linq.Expressions.Expression[])
        L_0066: ldc.i4.1 
        L_0067: newarr [System.Core]System.Linq.Expressions.ParameterExpression
        L_006c: stloc.2 
        L_006d: ldloc.2 
        L_006e: ldc.i4.0 
        L_006f: ldloc.0 
        L_0070: stelem.ref 
        L_0071: ldloc.2 
        L_0072: call class [System.Core]System.Linq.Expressions.Expression`1<!!0> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Func`2<class LinqToSqlTest.MyEntity, bool>>(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.ParameterExpression[])
        L_0077: call !!0 [System.Core]System.Linq.Queryable::FirstOrDefault<class LinqToSqlTest.MyEntity>(class [System.Core]System.Linq.IQueryable`1<!!0>, class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Func`2<!!0, bool>>)
        L_007c: pop 
        L_007d: ret 
    }

区别更大:

WithOperator 和WithEquals 区别

WithEquals 中,有一个额外的

[System.Core]System.Linq.Expressions.Expression[]

初始化,它在方法的中间调用了 Equals。

另外,我可以看到 WithOperator 使用

call class [System.Core]System.Linq.Expressions.BinaryExpression [System.Core]System.Linq.Expressions.Expression::Equal(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.Expression)

,而 WithEquals 使用

call class [System.Core]System.Linq.Expressions.MethodCallExpression [System.Core]System.Linq.Expressions.Expression::Call(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Reflection.MethodInfo, class [System.Core]System.Linq.Expressions.Expression[])

这是在第二张图片的 第 38 行中。

嗯,也许是 BinaryExpressionMethodCallExpression 之间的差异问题?我将针对这些进行进一步的研究。

等等

我们有一个工作

public void WithOperatorSelect(EntitiesDataContext ctx)
{
    ctx.GetTable<MyEntity>().Where(i => i.ID == 2).Select(i => i).FirstOrDefault();
}

相同

public void WithOperatorAndWhere(EntitiesDataContext ctx)
{
    ctx.GetTable<MyEntity>().Where(i => i.ID == 2).FirstOrDefault();
}

但有一个额外的假选择并且它工作

MSIL

WithOperatorAndSelect

.method public hidebysig instance void WithOperatorSelect(class LinqToSqlTest.EntitiesDataContext ctx) cil managed
    {
        .maxstack 5
        .locals init (
            [0] class [System.Core]System.Linq.Expressions.ParameterExpression CS$0$0000,
            [1] class [System.Core]System.Linq.Expressions.ParameterExpression[] CS$0$0001)
        L_0000: nop 
        L_0001: ldarg.1 
        L_0002: callvirt instance class [System.Data.Linq]System.Data.Linq.Table`1<!!0> [System.Data.Linq]System.Data.Linq.DataContext::GetTable<class LinqToSqlTest.MyEntity>()
        L_0007: ldtoken LinqToSqlTest.MyEntity
        L_000c: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
        L_0011: ldstr "i"
        L_0016: call class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Parameter(class [mscorlib]System.Type, string)
        L_001b: stloc.0 
        L_001c: ldloc.0 
        L_001d: ldtoken instance int64 LinqToSqlTest.EntityBase::get_ID()
        L_0022: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
        L_0027: castclass [mscorlib]System.Reflection.MethodInfo
        L_002c: call class [System.Core]System.Linq.Expressions.MemberExpression [System.Core]System.Linq.Expressions.Expression::Property(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Reflection.MethodInfo)
        L_0031: ldc.i4.2 
        L_0032: conv.i8 
        L_0033: box int64
        L_0038: ldtoken int64
        L_003d: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
        L_0042: call class [System.Core]System.Linq.Expressions.ConstantExpression [System.Core]System.Linq.Expressions.Expression::Constant(object, class [mscorlib]System.Type)
        L_0047: call class [System.Core]System.Linq.Expressions.BinaryExpression [System.Core]System.Linq.Expressions.Expression::Equal(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.Expression)
        L_004c: ldc.i4.1 
        L_004d: newarr [System.Core]System.Linq.Expressions.ParameterExpression
        L_0052: stloc.1 
        L_0053: ldloc.1 
        L_0054: ldc.i4.0 
        L_0055: ldloc.0 
        L_0056: stelem.ref 
        L_0057: ldloc.1 
        L_0058: call class [System.Core]System.Linq.Expressions.Expression`1<!!0> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Func`2<class LinqToSqlTest.MyEntity, bool>>(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.ParameterExpression[])
        L_005d: call class [System.Core]System.Linq.IQueryable`1<!!0> [System.Core]System.Linq.Queryable::Where<class LinqToSqlTest.MyEntity>(class [System.Core]System.Linq.IQueryable`1<!!0>, class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Func`2<!!0, bool>>)
        L_0062: ldtoken LinqToSqlTest.MyEntity
        L_0067: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
        L_006c: ldstr "i"
        L_0071: call class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Parameter(class [mscorlib]System.Type, string)
        L_0076: stloc.0 
        L_0077: ldloc.0 
        L_0078: ldc.i4.1 
        L_0079: newarr [System.Core]System.Linq.Expressions.ParameterExpression
        L_007e: stloc.1 
        L_007f: ldloc.1 
        L_0080: ldc.i4.0 
        L_0081: ldloc.0 
        L_0082: stelem.ref 
        L_0083: ldloc.1 
        L_0084: call class [System.Core]System.Linq.Expressions.Expression`1<!!0> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Func`2<class LinqToSqlTest.MyEntity, class LinqToSqlTest.MyEntity>>(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.ParameterExpression[])
        L_0089: call class [System.Core]System.Linq.IQueryable`1<!!1> [System.Core]System.Linq.Queryable::Select<class LinqToSqlTest.MyEntity, class LinqToSqlTest.MyEntity>(class [System.Core]System.Linq.IQueryable`1<!!0>, class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Func`2<!!0, !!1>>)
        L_008e: call !!0 [System.Core]System.Linq.Queryable::FirstOrDefault<class LinqToSqlTest.MyEntity>(class [System.Core]System.Linq.IQueryable`1<!!0>)
        L_0093: pop 
        L_0094: ret 
    }

WithOperatorAndWhere

 .method public hidebysig instance void WithOperatorAndWhere(class LinqToSqlTest.EntitiesDataContext ctx) cil managed
    {
        .maxstack 5
        .locals init (
            [0] class [System.Core]System.Linq.Expressions.ParameterExpression CS$0$0000,
            [1] class [System.Core]System.Linq.Expressions.ParameterExpression[] CS$0$0001)
        L_0000: nop 
        L_0001: ldarg.1 
        L_0002: callvirt instance class [System.Data.Linq]System.Data.Linq.Table`1<!!0> [System.Data.Linq]System.Data.Linq.DataContext::GetTable<class LinqToSqlTest.MyEntity>()
        L_0007: ldtoken LinqToSqlTest.MyEntity
        L_000c: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
        L_0011: ldstr "i"
        L_0016: call class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Parameter(class [mscorlib]System.Type, string)
        L_001b: stloc.0 
        L_001c: ldloc.0 
        L_001d: ldtoken instance int64 LinqToSqlTest.EntityBase::get_ID()
        L_0022: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
        L_0027: castclass [mscorlib]System.Reflection.MethodInfo
        L_002c: call class [System.Core]System.Linq.Expressions.MemberExpression [System.Core]System.Linq.Expressions.Expression::Property(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Reflection.MethodInfo)
        L_0031: ldc.i4.2 
        L_0032: conv.i8 
        L_0033: box int64
        L_0038: ldtoken int64
        L_003d: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
        L_0042: call class [System.Core]System.Linq.Expressions.ConstantExpression [System.Core]System.Linq.Expressions.Expression::Constant(object, class [mscorlib]System.Type)
        L_0047: call class [System.Core]System.Linq.Expressions.BinaryExpression [System.Core]System.Linq.Expressions.Expression::Equal(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.Expression)
        L_004c: ldc.i4.1 
        L_004d: newarr [System.Core]System.Linq.Expressions.ParameterExpression
        L_0052: stloc.1 
        L_0053: ldloc.1 
        L_0054: ldc.i4.0 
        L_0055: ldloc.0 
        L_0056: stelem.ref 
        L_0057: ldloc.1 
        L_0058: call class [System.Core]System.Linq.Expressions.Expression`1<!!0> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Func`2<class LinqToSqlTest.MyEntity, bool>>(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.ParameterExpression[])
        L_005d: call class [System.Core]System.Linq.IQueryable`1<!!0> [System.Core]System.Linq.Queryable::Where<class LinqToSqlTest.MyEntity>(class [System.Core]System.Linq.IQueryable`1<!!0>, class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Func`2<!!0, bool>>)
        L_0062: call !!0 [System.Core]System.Linq.Queryable::FirstOrDefault<class LinqToSqlTest.MyEntity>(class [System.Core]System.Linq.IQueryable`1<!!0>)
        L_0067: pop 
        L_0068: ret 
    }

区别:

 WithOperatorAndSelect 和 WithOperatorAndWhere 区别

唯一的区别(除了 WithOperatorAndSelect 有效:))是 MSIL 中的 Select 语句。

所以我猜这不是 == 运算符/等于问题。但我不知道。

It's a question about InvalidOperationException with message Class member X is unmapped.

One of our system has the same base entity for each LinqToSql entity with framework version 3.5.

I ran into a very strange problem and I started a research about it. I made a very small project to be able to localize the problem more easily.

Entity base class

public abstract class EntityBase
{
    public virtual long ID { get; set; }
}

DataContext and Entity

[Database(Name = "TestDatabase")]
public class EntitiesDataContext : DataContext
{
    public EntitiesDataContext() :
        base(Settings.Default.TestDatabaseConnectionString, new AttributeMappingSource())
    {
    }
}

[Table(Name = "dbo.MyEntity")]
public class MyEntity : EntityBase
{
    private long _EntityID;

    [Column(Name = "EntityID", Storage = "_EntityID")]
    public override long ID
    {
        get { return _EntityID; }
        set { _EntityID = value; }
    }

    [Column] public string Title;
}

The problem is the overriden ID. I made a lot of variation with different mapping attribute/property name setups, but it seems the problem is not the naming but the base class. And there is also a difference between .NET3.5 and .NET4.0.

So, for the following statements, imagine a

using (var ctx = new EntitiesDataContext())
{
    //statement
}

around.

And GetTable() is GetTable<MyEntity>().

Fails means Class member EntityBase.ID is unmapped. exception. Works means the expected behavior.

1 (in 3.5) WORKS:

var result = ctx.GetTable().Where(i => i.ID == 2).FirstOrDefault();

2 (in 3.5) FAILS:

var result = ctx.GetTable().FirstOrDefault(i => i.ID == 2);

3 (in 3.5) WORKS:

var result = ctx.GetTable().FirstOrDefault(i => i.ID.Equals(2));

4 (in 3.5) WORKS:

var result = ctx.GetTable().Where(i => true).FirstOrDefault(i => i.ID == 2);

5 (in 3.5) WORKS:

var result = ctx.GetTable().Where(i => i.ID == 2).FirstOrDefault();

6 (in 4.0) FAILS:

var result = ctx.GetTable().Where(i => i.ID == 2).FirstOrDefault()

7 (in 4.0) WORKS:

var result = ctx.GetTable().Where(i => i.ID.Equals(2)).FirstOrDefault();

8 (in 4.0) FAILS (redundant with 6)

var result = ctx.GetTable().FirstOrDefault(i => i.ID == 2);

9 (in 4.0) WORKS:

var result = ctx.GetTable().FirstOrDefault(i => i.ID.Equals(2));

10 (in 4.0) WORKS:

ctx.GetTable().Where(i => true).FirstOrDefault(i => i.ID == 2);

So
I cannot figure out why it fails where it fails. Especially, why this works

var result = ctx.GetTable().Where(i => true).FirstOrDefault(i => i.ID == 2);

if FirstOrDefault with predicate does not? And why Equals works where == is not.

I was looking for some Equals and == difference description, but it does not give me the answer for Where(i => true)... thing.

It seems that it's not about the query but the object initialization. Because:

in 4.0 WORKS:

var result = ctx.GetTable().Where(i => i.ID == 2).Select(i => i.Title).FirstOrDefault();

but :)

in 4.0 it's also WORKS:

var result = ctx.GetTable().FirstOrDefault();

So maybe not the object initialization?

The SQL being built by LinqToSql is the same for == and Equals. Also the same for

Where(i => true).FirstOrDefault(i => i.ID == 2)

and

FirstOrDefault(i => i.ID == 2)

There is no SQL query until FirstOrDefault, and it builds the query correctly, as it expected. Where(i => true) just continues the expression building and FirstOrDefault predicate included in the SQL queries.

I was looking for other reason in Reflector in MSIL, but found nothing special.

Any guess? :)

Thank you

####Continuation (in .NET4.0)

I set up 5 simple methods to easily check in reflector:

public void WithEquals(EntitiesDataContext ctx)
{
    ctx.GetTable<MyEntity>().FirstOrDefault(i => i.ID.Equals(2));
}

public void WithFakeWhereAndOperator(EntitiesDataContext ctx)
{
    ctx.GetTable<MyEntity>().Where(i => true).FirstOrDefault(i => i.ID == 2);
}

public void WithOperator(EntitiesDataContext ctx)
{
    ctx.GetTable<MyEntity>().FirstOrDefault(i => i.ID == 2);
}

public void WithOperatorSelect(EntitiesDataContext ctx)
{
    ctx.GetTable<MyEntity>().Where(i => i.ID == 2).Select(i => i).FirstOrDefault();
}

public void WithOperatorAndWhere(EntitiesDataContext ctx)
{
    ctx.GetTable<MyEntity>().Where(i => i.ID == 2).FirstOrDefault();
}

WithOperator and WithOperatorAndWhere fails, but here is the MSIL and what I see:

WithOperator

  .method public hidebysig instance void WithOperator(class LinqToSqlTest.EntitiesDataContext ctx) cil managed
    {
        .maxstack 5
        .locals init (
            [0] class [System.Core]System.Linq.Expressions.ParameterExpression CS$0$0000,
            [1] class [System.Core]System.Linq.Expressions.ParameterExpression[] CS$0$0001)
        L_0000: nop 
        L_0001: ldarg.1 
        L_0002: callvirt instance class [System.Data.Linq]System.Data.Linq.Table`1<!!0> [System.Data.Linq]System.Data.Linq.DataContext::GetTable<class LinqToSqlTest.MyEntity>()
        L_0007: ldtoken LinqToSqlTest.MyEntity
        L_000c: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
        L_0011: ldstr "i"
        L_0016: call class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Parameter(class [mscorlib]System.Type, string)
        L_001b: stloc.0 
        L_001c: ldloc.0 
        L_001d: ldtoken instance int64 LinqToSqlTest.EntityBase::get_ID()
        L_0022: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
        L_0027: castclass [mscorlib]System.Reflection.MethodInfo
        L_002c: call class [System.Core]System.Linq.Expressions.MemberExpression [System.Core]System.Linq.Expressions.Expression::Property(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Reflection.MethodInfo)
        L_0031: ldc.i4.2 
        L_0032: conv.i8 
        L_0033: box int64
        L_0038: ldtoken int64
        L_003d: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
        L_0042: call class [System.Core]System.Linq.Expressions.ConstantExpression [System.Core]System.Linq.Expressions.Expression::Constant(object, class [mscorlib]System.Type)
        L_0047: call class [System.Core]System.Linq.Expressions.BinaryExpression [System.Core]System.Linq.Expressions.Expression::Equal(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.Expression)
        L_004c: ldc.i4.1 
        L_004d: newarr [System.Core]System.Linq.Expressions.ParameterExpression
        L_0052: stloc.1 
        L_0053: ldloc.1 
        L_0054: ldc.i4.0 
        L_0055: ldloc.0 
        L_0056: stelem.ref 
        L_0057: ldloc.1 
        L_0058: call class [System.Core]System.Linq.Expressions.Expression`1<!!0> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Func`2<class LinqToSqlTest.MyEntity, bool>>(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.ParameterExpression[])
        L_005d: call !!0 [System.Core]System.Linq.Queryable::FirstOrDefault<class LinqToSqlTest.MyEntity>(class [System.Core]System.Linq.IQueryable`1<!!0>, class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Func`2<!!0, bool>>)
        L_0062: pop 
        L_0063: ret 
    }

WithFakeWhereAndOperator

 .method public hidebysig instance void WithFakeWhereAndOperator(class LinqToSqlTest.EntitiesDataContext ctx) cil managed
    {
        .maxstack 5
        .locals init (
            [0] class [System.Core]System.Linq.Expressions.ParameterExpression CS$0$0000,
            [1] class [System.Core]System.Linq.Expressions.ParameterExpression[] CS$0$0001)
        L_0000: nop 
        L_0001: ldarg.1 
        L_0002: callvirt instance class [System.Data.Linq]System.Data.Linq.Table`1<!!0> [System.Data.Linq]System.Data.Linq.DataContext::GetTable<class LinqToSqlTest.MyEntity>()
        L_0007: ldtoken LinqToSqlTest.MyEntity
        L_000c: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
        L_0011: ldstr "i"
        L_0016: call class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Parameter(class [mscorlib]System.Type, string)
        L_001b: stloc.0 
        L_001c: ldc.i4.1 
        L_001d: box bool
        L_0022: ldtoken bool
        L_0027: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
        L_002c: call class [System.Core]System.Linq.Expressions.ConstantExpression [System.Core]System.Linq.Expressions.Expression::Constant(object, class [mscorlib]System.Type)
        L_0031: ldc.i4.1 
        L_0032: newarr [System.Core]System.Linq.Expressions.ParameterExpression
        L_0037: stloc.1 
        L_0038: ldloc.1 
        L_0039: ldc.i4.0 
        L_003a: ldloc.0 
        L_003b: stelem.ref 
        L_003c: ldloc.1 
        L_003d: call class [System.Core]System.Linq.Expressions.Expression`1<!!0> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Func`2<class LinqToSqlTest.MyEntity, bool>>(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.ParameterExpression[])
        L_0042: call class [System.Core]System.Linq.IQueryable`1<!!0> [System.Core]System.Linq.Queryable::Where<class LinqToSqlTest.MyEntity>(class [System.Core]System.Linq.IQueryable`1<!!0>, class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Func`2<!!0, bool>>)
        L_0047: ldtoken LinqToSqlTest.MyEntity
        L_004c: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
        L_0051: ldstr "i"
        L_0056: call class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Parameter(class [mscorlib]System.Type, string)
        L_005b: stloc.0 
        L_005c: ldloc.0 
        L_005d: ldtoken instance int64 LinqToSqlTest.EntityBase::get_ID()
        L_0062: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
        L_0067: castclass [mscorlib]System.Reflection.MethodInfo
        L_006c: call class [System.Core]System.Linq.Expressions.MemberExpression [System.Core]System.Linq.Expressions.Expression::Property(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Reflection.MethodInfo)
        L_0071: ldc.i4.2 
        L_0072: conv.i8 
        L_0073: box int64
        L_0078: ldtoken int64
        L_007d: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
        L_0082: call class [System.Core]System.Linq.Expressions.ConstantExpression [System.Core]System.Linq.Expressions.Expression::Constant(object, class [mscorlib]System.Type)
        L_0087: call class [System.Core]System.Linq.Expressions.BinaryExpression [System.Core]System.Linq.Expressions.Expression::Equal(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.Expression)
        L_008c: ldc.i4.1 
        L_008d: newarr [System.Core]System.Linq.Expressions.ParameterExpression
        L_0092: stloc.1 
        L_0093: ldloc.1 
        L_0094: ldc.i4.0 
        L_0095: ldloc.0 
        L_0096: stelem.ref 
        L_0097: ldloc.1 
        L_0098: call class [System.Core]System.Linq.Expressions.Expression`1<!!0> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Func`2<class LinqToSqlTest.MyEntity, bool>>(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.ParameterExpression[])
        L_009d: call !!0 [System.Core]System.Linq.Queryable::FirstOrDefault<class LinqToSqlTest.MyEntity>(class [System.Core]System.Linq.IQueryable`1<!!0>, class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Func`2<!!0, bool>>)
        L_00a2: pop 
        L_00a3: ret 
    }

As I see, there is no difference between the FirstOrDefault calls, the WithFakeWhereAndOperator only 'includes' a few line about the Where statement:

WithFakeWhereAndOperator and WithOperator difference

And the WithEquals

.method public hidebysig instance void WithEquals(class LinqToSqlTest.EntitiesDataContext ctx) cil managed
    {
        .maxstack 7
        .locals init (
            [0] class [System.Core]System.Linq.Expressions.ParameterExpression CS$0$0000,
            [1] class [System.Core]System.Linq.Expressions.Expression[] CS$0$0001,
            [2] class [System.Core]System.Linq.Expressions.ParameterExpression[] CS$0$0002)
        L_0000: nop 
        L_0001: ldarg.1 
        L_0002: callvirt instance class [System.Data.Linq]System.Data.Linq.Table`1<!!0> [System.Data.Linq]System.Data.Linq.DataContext::GetTable<class LinqToSqlTest.MyEntity>()
        L_0007: ldtoken LinqToSqlTest.MyEntity
        L_000c: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
        L_0011: ldstr "i"
        L_0016: call class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Parameter(class [mscorlib]System.Type, string)
        L_001b: stloc.0 
        L_001c: ldloc.0 
        L_001d: ldtoken instance int64 LinqToSqlTest.EntityBase::get_ID()
        L_0022: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
        L_0027: castclass [mscorlib]System.Reflection.MethodInfo
        L_002c: call class [System.Core]System.Linq.Expressions.MemberExpression [System.Core]System.Linq.Expressions.Expression::Property(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Reflection.MethodInfo)
        L_0031: ldtoken instance bool [mscorlib]System.Int64::Equals(int64)
        L_0036: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
        L_003b: castclass [mscorlib]System.Reflection.MethodInfo
        L_0040: ldc.i4.1 
        L_0041: newarr [System.Core]System.Linq.Expressions.Expression
        L_0046: stloc.1 
        L_0047: ldloc.1 
        L_0048: ldc.i4.0 
        L_0049: ldc.i4.2 
        L_004a: conv.i8 
        L_004b: box int64
        L_0050: ldtoken int64
        L_0055: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
        L_005a: call class [System.Core]System.Linq.Expressions.ConstantExpression [System.Core]System.Linq.Expressions.Expression::Constant(object, class [mscorlib]System.Type)
        L_005f: stelem.ref 
        L_0060: ldloc.1 
        L_0061: call class [System.Core]System.Linq.Expressions.MethodCallExpression [System.Core]System.Linq.Expressions.Expression::Call(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Reflection.MethodInfo, class [System.Core]System.Linq.Expressions.Expression[])
        L_0066: ldc.i4.1 
        L_0067: newarr [System.Core]System.Linq.Expressions.ParameterExpression
        L_006c: stloc.2 
        L_006d: ldloc.2 
        L_006e: ldc.i4.0 
        L_006f: ldloc.0 
        L_0070: stelem.ref 
        L_0071: ldloc.2 
        L_0072: call class [System.Core]System.Linq.Expressions.Expression`1<!!0> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Func`2<class LinqToSqlTest.MyEntity, bool>>(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.ParameterExpression[])
        L_0077: call !!0 [System.Core]System.Linq.Queryable::FirstOrDefault<class LinqToSqlTest.MyEntity>(class [System.Core]System.Linq.IQueryable`1<!!0>, class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Func`2<!!0, bool>>)
        L_007c: pop 
        L_007d: ret 
    }

The difference is bigger:

WithOperator and WithEquals difference

In WithEquals, there is an extra

[System.Core]System.Linq.Expressions.Expression[]

initialization, and it calls Equals in the middle of the method.

Also, I can see that WithOperator uses

call class [System.Core]System.Linq.Expressions.BinaryExpression [System.Core]System.Linq.Expressions.Expression::Equal(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.Expression)

while WithEquals uses

call class [System.Core]System.Linq.Expressions.MethodCallExpression [System.Core]System.Linq.Expressions.Expression::Call(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Reflection.MethodInfo, class [System.Core]System.Linq.Expressions.Expression[])

This is in the line 38 on the second image.

Hm, maybe it's a problem about the difference between BinaryExpression and MethodCallExpression? I will make further research about these.

So on

We have a working

public void WithOperatorSelect(EntitiesDataContext ctx)
{
    ctx.GetTable<MyEntity>().Where(i => i.ID == 2).Select(i => i).FirstOrDefault();
}

Same as

public void WithOperatorAndWhere(EntitiesDataContext ctx)
{
    ctx.GetTable<MyEntity>().Where(i => i.ID == 2).FirstOrDefault();
}

but with an extra fake select and it works.

MSIL

WithOperatorAndSelect

.method public hidebysig instance void WithOperatorSelect(class LinqToSqlTest.EntitiesDataContext ctx) cil managed
    {
        .maxstack 5
        .locals init (
            [0] class [System.Core]System.Linq.Expressions.ParameterExpression CS$0$0000,
            [1] class [System.Core]System.Linq.Expressions.ParameterExpression[] CS$0$0001)
        L_0000: nop 
        L_0001: ldarg.1 
        L_0002: callvirt instance class [System.Data.Linq]System.Data.Linq.Table`1<!!0> [System.Data.Linq]System.Data.Linq.DataContext::GetTable<class LinqToSqlTest.MyEntity>()
        L_0007: ldtoken LinqToSqlTest.MyEntity
        L_000c: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
        L_0011: ldstr "i"
        L_0016: call class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Parameter(class [mscorlib]System.Type, string)
        L_001b: stloc.0 
        L_001c: ldloc.0 
        L_001d: ldtoken instance int64 LinqToSqlTest.EntityBase::get_ID()
        L_0022: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
        L_0027: castclass [mscorlib]System.Reflection.MethodInfo
        L_002c: call class [System.Core]System.Linq.Expressions.MemberExpression [System.Core]System.Linq.Expressions.Expression::Property(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Reflection.MethodInfo)
        L_0031: ldc.i4.2 
        L_0032: conv.i8 
        L_0033: box int64
        L_0038: ldtoken int64
        L_003d: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
        L_0042: call class [System.Core]System.Linq.Expressions.ConstantExpression [System.Core]System.Linq.Expressions.Expression::Constant(object, class [mscorlib]System.Type)
        L_0047: call class [System.Core]System.Linq.Expressions.BinaryExpression [System.Core]System.Linq.Expressions.Expression::Equal(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.Expression)
        L_004c: ldc.i4.1 
        L_004d: newarr [System.Core]System.Linq.Expressions.ParameterExpression
        L_0052: stloc.1 
        L_0053: ldloc.1 
        L_0054: ldc.i4.0 
        L_0055: ldloc.0 
        L_0056: stelem.ref 
        L_0057: ldloc.1 
        L_0058: call class [System.Core]System.Linq.Expressions.Expression`1<!!0> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Func`2<class LinqToSqlTest.MyEntity, bool>>(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.ParameterExpression[])
        L_005d: call class [System.Core]System.Linq.IQueryable`1<!!0> [System.Core]System.Linq.Queryable::Where<class LinqToSqlTest.MyEntity>(class [System.Core]System.Linq.IQueryable`1<!!0>, class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Func`2<!!0, bool>>)
        L_0062: ldtoken LinqToSqlTest.MyEntity
        L_0067: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
        L_006c: ldstr "i"
        L_0071: call class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Parameter(class [mscorlib]System.Type, string)
        L_0076: stloc.0 
        L_0077: ldloc.0 
        L_0078: ldc.i4.1 
        L_0079: newarr [System.Core]System.Linq.Expressions.ParameterExpression
        L_007e: stloc.1 
        L_007f: ldloc.1 
        L_0080: ldc.i4.0 
        L_0081: ldloc.0 
        L_0082: stelem.ref 
        L_0083: ldloc.1 
        L_0084: call class [System.Core]System.Linq.Expressions.Expression`1<!!0> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Func`2<class LinqToSqlTest.MyEntity, class LinqToSqlTest.MyEntity>>(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.ParameterExpression[])
        L_0089: call class [System.Core]System.Linq.IQueryable`1<!!1> [System.Core]System.Linq.Queryable::Select<class LinqToSqlTest.MyEntity, class LinqToSqlTest.MyEntity>(class [System.Core]System.Linq.IQueryable`1<!!0>, class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Func`2<!!0, !!1>>)
        L_008e: call !!0 [System.Core]System.Linq.Queryable::FirstOrDefault<class LinqToSqlTest.MyEntity>(class [System.Core]System.Linq.IQueryable`1<!!0>)
        L_0093: pop 
        L_0094: ret 
    }

WithOperatorAndWhere

 .method public hidebysig instance void WithOperatorAndWhere(class LinqToSqlTest.EntitiesDataContext ctx) cil managed
    {
        .maxstack 5
        .locals init (
            [0] class [System.Core]System.Linq.Expressions.ParameterExpression CS$0$0000,
            [1] class [System.Core]System.Linq.Expressions.ParameterExpression[] CS$0$0001)
        L_0000: nop 
        L_0001: ldarg.1 
        L_0002: callvirt instance class [System.Data.Linq]System.Data.Linq.Table`1<!!0> [System.Data.Linq]System.Data.Linq.DataContext::GetTable<class LinqToSqlTest.MyEntity>()
        L_0007: ldtoken LinqToSqlTest.MyEntity
        L_000c: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
        L_0011: ldstr "i"
        L_0016: call class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Parameter(class [mscorlib]System.Type, string)
        L_001b: stloc.0 
        L_001c: ldloc.0 
        L_001d: ldtoken instance int64 LinqToSqlTest.EntityBase::get_ID()
        L_0022: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
        L_0027: castclass [mscorlib]System.Reflection.MethodInfo
        L_002c: call class [System.Core]System.Linq.Expressions.MemberExpression [System.Core]System.Linq.Expressions.Expression::Property(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Reflection.MethodInfo)
        L_0031: ldc.i4.2 
        L_0032: conv.i8 
        L_0033: box int64
        L_0038: ldtoken int64
        L_003d: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
        L_0042: call class [System.Core]System.Linq.Expressions.ConstantExpression [System.Core]System.Linq.Expressions.Expression::Constant(object, class [mscorlib]System.Type)
        L_0047: call class [System.Core]System.Linq.Expressions.BinaryExpression [System.Core]System.Linq.Expressions.Expression::Equal(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.Expression)
        L_004c: ldc.i4.1 
        L_004d: newarr [System.Core]System.Linq.Expressions.ParameterExpression
        L_0052: stloc.1 
        L_0053: ldloc.1 
        L_0054: ldc.i4.0 
        L_0055: ldloc.0 
        L_0056: stelem.ref 
        L_0057: ldloc.1 
        L_0058: call class [System.Core]System.Linq.Expressions.Expression`1<!!0> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Func`2<class LinqToSqlTest.MyEntity, bool>>(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.ParameterExpression[])
        L_005d: call class [System.Core]System.Linq.IQueryable`1<!!0> [System.Core]System.Linq.Queryable::Where<class LinqToSqlTest.MyEntity>(class [System.Core]System.Linq.IQueryable`1<!!0>, class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Func`2<!!0, bool>>)
        L_0062: call !!0 [System.Core]System.Linq.Queryable::FirstOrDefault<class LinqToSqlTest.MyEntity>(class [System.Core]System.Linq.IQueryable`1<!!0>)
        L_0067: pop 
        L_0068: ret 
    }

And the difference:

WithOperatorAndSelect and WithOperatorAndWhere difference

The only difference (in addition to that WithOperatorAndSelect works :) ) is the Select statement in MSIL.

So I guess it's not an == operator / Equals problem. But I don't know.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

与他有关 2024-12-15 04:20:44

我会在黑暗中刺一下这里。也许这与 == 是静态的而 .Equals() 是虚拟的有关。

因此,您最终会得到如下行为:

object x = 10;
object y = 10;

x == y      // returns false as == is static and the compiler statically binds it
            // to object, which uses a reference comparison, hence the false

x.Equals(y) // returns true as .Equals is virtual, thus calls the Int32 
            // implementation of .Equals which does a value type compare.

也许 linqtosql 无法确定您在使用“==”时所指的 ID - 它认为它是基类类型,而使用 .Equals () 它知道你指的是你的具体子类并且可以弄清楚。

我不知道,只是猜测...

I'll have a stab in the dark here. Perhaps it's got something to do with == being staic and .Equals() is virtual.

Because of this, you'd end up with behaviour like so:

object x = 10;
object y = 10;

x == y      // returns false as == is static and the compiler statically binds it
            // to object, which uses a reference comparison, hence the false

x.Equals(y) // returns true as .Equals is virtual, thus calls the Int32 
            // implementation of .Equals which does a value type compare.

Perhaps linqtosql can't determine which ID you're referring to when you're using "==" - it thinks it's of the base class type, whereas with .Equals() it knows you're referring to your concrete sub class and can figure it out.

I dunno, just a guess...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文