3

ユーザーが管理者でない限り、ユーザーが所有する注文のみを編集できるようにする UpdateOrders というメソッドがあります。管理者の場合、すべての注文を編集できます。

.NET 4.5 で Entity Framework 5 を使用しています。

次のコードは、行で「タイプ 'User' の定数値を作成できません」というエラーを生成しますvar target = _context.Orders.FirstOrDefault...

public Order UpdateOrders(Order order)
{
    var userName = HttpContext.Current.User.Identity.Name.ToLower();

    var target = _context.Orders.FirstOrDefault(o => o.OrderID == order.OrderID
        && (o.User.UserName.ToLower() == userName || _context.Users.FirstOrDefault(u => u.UserName == userName).Role.RoleName == "Administrator"));

    if (target != null)
    {
        _context.Entry(target).CurrentValues.SetValues(order);
        _context.SaveChanges();
    }

    return target;
}

RoleName を変数に設定する別の行を削除_context.Users.FirstOrDefault(u => u.UserName == userName).Role.RoleNameして、その変数をコードに入れると問題なく動作しますが、データベースにもう一度ヒットすることになります。

私が使用する場合_context.Orders.Where、エラーは発生せず、単一のクエリですべてのロジックを実行します。したがって、このコードは実際には問題なく動作します。

public void TestMethod(Order order)
{
    var userName = HttpContext.Current.User.Identity.Name.ToLower();

    var target = _context.Orders.Where(o => o.OrderID == order.OrderID
        && (o.User.UserName.ToLower() == userName || _context.Users.FirstOrDefault(u => u.UserName == userName).Role.RoleName == "Administrator")).ToList();

    return;
}

FirstOrDefault問題がWhereないのはなぜですか?目的の結果を取得し、すべてのロジックを単一のクエリに保持する方法はありますか?

ありがとう!

4

1 に答える 1

4

Entity Framework のバグを実際に発見したと思います。うらやましい!

(編集: このバグは EF 6.0.0-rc1 で修正されたようです)

これがバグだと思う理由は次のとおりです。式の述語を変換している機械は、FirstOrDefaultでは発生しない方法で、確実に誤動作していますWhere。これらの人為的なクエリを使用して、同様のスキーマに対して問題を再現できます。

// works
var target = _context.Orders.Where (o => _context.Users.FirstOrDefault() != null).FirstOrDefault ();

// Exception: Unable to create a constant value...
target = _context.Orders.FirstOrDefault (o => _context.Users.FirstOrDefault() != null);

例外をスローするだけでなく、LINQPad で SQL を観察すると、呼び出しをバージョンではなくバージョンとしてSELECT * FROM Users処理しようとしているかのように、効果的なクエリが爆発する直前に発行されていることがわかります。内部呼び出しでマップされていないメソッドを述語として使用すると、予想される「LINQ to Entities がメソッドを認識しない」例外ではなく、同じ「定数値」例外が発生します。_context.Users.FirstOrDefault()IEnumerableIQueryableFirstOrDefault

// throws "Unable to create a constant value..." exception!
target = _context.Orders.FirstOrDefault (o => _context.Users.FirstOrDefault(u => MyBogusMethod(u)) != null);

トランスレータ forは、何らかの方法で式を実行することにより、型の式を積極的に型のインスタンスにFirstOrDefault削減しようとしているかのようですが、削減が完了する前 (内部が評価される前) に、結果の型がそうではないことに気付きます。許可されて爆発します。非常に奇妙な。UserUserFirstOrDefault

ソースで何が問題なのかを簡単に理解しようとしましたが、それは私をはるかに超えています.EF の人たちにバグを報告することをお勧めします: http://entityframework.codeplex.com/workitem/list/basic

それまでの間、クエリの最後にタグを付けたとしても、述語をWhereではなく句に入れている限り、正しく機能するようです。FirstOrDefaultFirstOrDefault

var target = _context.Orders.Where(o => 
              o.OrderID == order.OrderID
              && (o.User.UserName.ToLower() == userName 
                  || _context.Users.FirstOrDefault(u => 
                       u.UserName == userName).Role.RoleName == "Administrator")
              )
              .FirstOrDefault();

User(このような複雑なクエリの必要性を避けるために、ユーザーが で「管理者」ロールを持っているという事実を保存することも検討してください。)

于 2013-09-04T23:22:28.603 に答える