1

cshtml でパブリック クラスのオブジェクトを使用したいのですが、実行時エラーが発生しました: LINQ to Entities では、パラメーターなしのコンストラクターと初期化子のみがサポートされています。次のステートメントのどこが間違っていますか? 助けてくれてありがとう!

@foreach (var obj in ViewData["IncompleteList"] as IEnumerable<Games.TeamAction>)

コントローラーは、次のように ViewBag を埋めます。

IEnumerable<TeamAction> incomplete = dbIncAct.IncompleteActivity.Where(a => a.activityID == id)
                                .Select(s => new TeamAction(s.teamID, s.name, id, s.type));
ViewBag.IncompleteList = incomplete;

クラス TeamAction (名前空間 Games の一部) は非常に単純です。

public class TeamAction
{
    public TeamAction()
    {
    }

    ....

    public int teamID {get; set;}
    public string teamName { get; set; }
    public int activityID { get; set; }
    public int actionType { get; set; }
}
4

2 に答える 2

5

答えは、エラーメッセージの解釈方法がわかれば、エラーメッセージにあります。

IEnumerable次のように、LINQ to Entities (Entity Framework LINQ プロバイダー) 経由で作成しています。

IEnumerable<TeamAction> incomplete = dbIncAct.IncompleteActivity
  .Where(a => a.activityID == id)
  .Select(s => new TeamAction(s.teamID, s.name, id, s.type));

呼び出しには、 4 つのパラメーターを受け取るコンストラクターをSelect呼び出すラムダ式が含まれていることに注意してください。TeamActionの最初の要素を要求するとすぐにIEnumerable、LINQ はクエリを実行しようとします。その時点で、ラムダ式を解析し、実行可能な Entity Framework クエリに変換しようとします。しかし、例外メッセージが示すように:

Only parameterless constructors and initializers are supported 

LINQ to Entities は実行方法を認識していないため、パラメーター化されたコンストラクターを LINQ クエリに含めることはできません。問題を解決するには、いくつかのオプションがあります。

オプション 1: IQueryable -> IEnumerable

これを回避する最も簡単な方法は、EF LINQ プロバイダーが問題のあるラムダを認識しないようにするIQueryableことIEnumerableです。dbIncAct.ImcompleteActivityはおそらく でありDbSet<>、まだ LINQ 2 エンティティに依存しているをDbSet<>.Where返します。IQueryableその依存関係を断ち切るには、次のようにします。

IEnumerable<TeamAction> incomplete = dbIncAct.IncompleteActivity
  .Where(a => a.activityID == id)
  .AsEnumerable()
  .Select(s => new TeamAction(s.teamID, s.name, id, s.type));

これにより、EF クエリが強制的にパーツを実行し、エンティティWhereの列挙可能なコレクションが返されます。IncompleteActivityそのこと (内部で定義された のようなオブジェクト) は、EF とは完全に別のList呼び出しに使用されます。Select

ここでの欠点は、おそらくデータベースにヒットする EF クエリをすぐに実行するように強制していることです。それが望ましくない場合は、他の 2 つのオプションのいずれかを使用して、パラメーター化されたコンストラクターを削除するしかありません。

オプション 2: オブジェクト初期化子

そのコンストラクターが何をしたかによって、簡単に修正できる場合とできない場合があります。コンストラクターが、新しく作成されたオブジェクトのプロパティを設定するためだけにある場合は、幸運です。C# は、まさにこの理由から、LINQ およびラムダと連携する新しいオブジェクト初期化子構文を導入しました。

IEnumerable<TeamAction> incomplete = dbIncAct.IncompleteActivity
  .Where(a => a.activityID == id)
  .Select(s => new TeamAction 
  { 
    TeamId = s.teamID, 
    Name = s.name,
    Id = id, 
    Type = s.type
  });

オプション 3: リファクタリング

コンストラクターが実際の作業を行う場合は、リファクタリングを行う必要があります。できるだけ多くのロジックをデフォルトTeamAction()コンストラクターに移動してみてください。ロジックの一部をプロパティ セッターに入れることもできますが、できる限り最小限に抑える必要があります。

オブジェクトが実際に複雑な初期化を必要とする場合、ライフサイクルの早い段階で呼び出される初期化メソッドを持つ典型的なパターンは次のとおりです。

var x = new X { ... };  
x.InitializeMe();

これは、たとえば@forループ内で行うことも、クエリを作成した直後の別のステップとして行うこともできます。

于 2012-11-12T16:27:47.257 に答える
0

代わりにオブジェクトの初期化に変更します。

IEnumerable<TeamAction> incomplete = dbIncAct.IncompleteActivity.Where(a => a.activityID == id)
                            .Select(s => new TeamAction { teamID = s.teamID, teamName = s.name, activityID = s.id, actionType = s.type });
于 2012-11-12T16:17:43.467 に答える