Интересное поведение общего базового класса в Linq to SQL - PullRequest
9 голосов
/ 06 октября 2011

Это вопрос о InvalidOperationException с сообщением Член класса X не сопоставлен.

Одна из наших систем имеет одинаковую базовую сущность для каждой сущности LinqToSql с версией платформы 3.5.

Я столкнулся с очень странной проблемой и начал исследовать ее. Я сделал очень маленький проект, чтобы легче было локализовать проблему.

Базовый класс сущности

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

DataContext и 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;
}

Проблема в переопределении ID . Я внес много изменений в различные настройки сопоставления атрибутов / имен свойств, но, похоже, проблема не в именовании, а в базовом классе . И есть также разница между .NET3.5 и .NET4.0.

Итак, для следующих утверждений представьте

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

вокруг.

И GetTable () составляет GetTable<MyEntity>().

Сбой означает Элемент класса EntityBase.ID не отображен. исключение. Работает означает ожидаемое поведение.

1 (в 3.5) РАБОТАЕТ:

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

2 (в 3.5) FAILS :

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) FAILS :

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) FAILS (избыточно с 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);

So Я не могу понять, почему это терпит неудачу, где это терпит неудачу. Особенно, почему это работает

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

если FirstOrDefault с предикатом не имеет? И почему Equals работает там, где == нет.

Я искал описание равенства и ==, но оно не дает мне ответа на вопрос Где (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();

Так может не инициализация объекта ?

SQL, создаваемый LinqToSql - это то же самое для == и Equals. Также то же самое для

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

и

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

Нет запроса SQL до FirstOrDefault, и он правильно строит запрос, как и ожидалось. Где (i => true) просто продолжает построение выражения и предикат FirstOrDefault, включенный в запросы SQL.

Я искал другую причину в Reflector в MSIL , но ничего особенного не нашел.

Есть предположения? :)

Спасибо

#### Продолжение (в .NET4.0)

Я установил 5 простых способов легко зарегистрировать отражатель :

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 and WithOperator difference

И СEquals

.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 and WithEquals difference

В СEquals , есть дополнительный

[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 на втором изображении.

Хм, может проблема в разнице между BinaryExpression и MethodCallExpression ? Я сделаю дальнейшее исследование об этом.

Итак

У нас есть рабочий

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 and WithOperatorAndWhere difference

Единственное отличие (в дополнение к тому, что WithOperatorAndSelect работает :)) - это оператор Select в MSIL.

Так что я думаю это не проблема == оператор / равно. Но я не знаю.

Ответы [ 2 ]

5 голосов
/ 15 октября 2011

Хорошо, похоже, это известная ошибка:

http://connect.microsoft.com/VisualStudio/feedback/details/394255/linq-to-sql-bug-handling-entities-with-common-base-class

и это не будет исправлено.

Похожие вопросы:

LINQ to SQL - исключение при отображении при использовании абстрактных базовых классов

LinqToSql и абстрактные базовые классы

В любом случае, спасибо Фрэнку Цанабетису за ваши усилия.

2 голосов
/ 07 октября 2011

У меня здесь будет удар в темноте. Возможно, это как-то связано с тем, что == является staic, а .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 не может определить, на какой идентификатор вы ссылаетесь, когда используете "==" - он думает, что это тип базового класса, тогда как .Equals () знает, что вы ссылаетесь на ваш конкретный подкласс и может понять это.

Не знаю, просто предположение ...

...