[C#] エンティティをLINQ to Entitiesクエリで構築することはできません


Answers

あなたは匿名型に投影し、次にそれをモデル型に投影することができます

public IEnumerable<Product> GetProducts(int categoryID)
{
    return (from p in Context.Set<Product>()
            where p.CategoryID == categoryID
            select new { Name = p.Name }).ToList()
           .Select(x => new Product { Name = x.Name });
}

編集 :この質問は多くの注目を集めているので、もう少し具体的にするつもりです。

モデルタイプに直接投影することはできません(EF制限)ので、これを回避する方法はありません。 唯一の方法は、匿名型(1回目の反復)に投影し、次にモデル型(2回目の反復)に投影することです。

この方法でエンティティを部分的に読み込むと、エンティティを更新することはできないので、エンティティをそのまま引き離しておく必要があることに注意してください。

私はこれがなぜ不可能であるのかを完全に理解したことは一度もありませんでした。このスレッドの答えは、主に部分的に読み込まれたデータに関する強い理由を与えていません。 部分的にロードされた状態エンティティを更新することはできないが、このエンティティは切り離されるため、偶発的にそれらを保存しようとする試みは不可能であるということは正しい。

上記で使用したメソッドIを検討してください。結果として部分的にロードされたモデルエンティティがまだあります。 このエンティティはデタッチされます。

可能なコードを考えてみましょう:

return (from p in Context.Set<Product>()
        where p.CategoryID == categoryID
        select new Product { Name = p.Name }).AsNoTracking().ToList();

これにより、分離されたエンティティのリストが生成される可能性があります。したがって、2回繰り返す必要はありません。 コンパイラはAsNoTracking()が使用されていることを知り、分離されたエンティティになりますので、これを行うことができます。 ただし、AsNoTracking()を省略した場合、現在の結果と同じ例外がスローされ、必要な結果について十分に具体的にする必要があることを警告できます。

Question

エンティティフレームワークによって生成されるproductというエンティティタイプがあります。 私はこの質問を書いた

public IQueryable<Product> GetProducts(int categoryID)
{
    return from p in db.Products
           where p.CategoryID== categoryID
           select new Product { Name = p.Name};
}

次のコードは、次のエラーをスローします。

"エンティティまたは複合型のShop.ProductをLINQ to Entitiesクエリで構築できません"

var products = productRepository.GetProducts(1).Tolist();

しかし、私はselect p代わりにselect new Product { Name = p.Name};を使用しselect p select new Product { Name = p.Name}; それは正しく動作します。

どのようにカスタム選択セクションをプリフォームできますか?




ここでは、宣言クラスを宣言せずにこれを行う方法の1つです:

public List<Product> GetProducts(int categoryID)
{
    var query = from p in db.Products
            where p.CategoryID == categoryID
            select new { Name = p.Name };
    var products = query.ToList().Select(r => new Product
    {
        Name = r.Name;
    }).ToList();

    return products;
}

ただし、これは、単一のエンティティで複数のエンティティを結合する場合にのみ使用します。 上記の機能(単純な製品から製品へのマッピング)は次のように行われます。

public List<Product> GetProducts(int categoryID)
{
    var query = from p in db.Products
            where p.CategoryID == categoryID
            select p;
    var products = query.ToList();

    return products;
}



あなたはこれを使うことができ、うまくいくはずです - > selectを使って新しいリストを作る前にtoList使う必要があります:

db.Products
    .where(x=>x.CategoryID == categoryID).ToList()
    .select(x=>new Product { Name = p.Name}).ToList(); 



重複しているとマークされた他の質問に答えて( ここを参照 )、私はソレンの答えに基づいて、すばやく簡単な解決策を見つけました:

data.Tasks.AddRange(
    data.Task.AsEnumerable().Select(t => new Task{
        creator_id   = t.ID,
        start_date   = t.Incident.DateOpened,
        end_date     = t.Incident.DateCLosed,
        product_code = t.Incident.ProductCode
        // so on...
    })
);
data.SaveChanges();

注:このソリューションは、タスククラス(ここでは「インシデント」)にナビゲーションプロパティ(外部キー)がある場合にのみ機能します。 あなたがそれを持っていない場合、あなたは単に "AsQueryable()"と他の投稿されたソリューションの1つを使用することができます。




Linq to Entityを実行している場合、クエリのselectクロージャでClassTypenewで使用することはできません。 only anonymous types are allowed (new without type)

私のプロジェクトのこのスニペットを見てください

//...
var dbQuery = context.Set<Letter>()
                .Include(letter => letter.LetterStatus)
                .Select(l => new {Title =l.Title,ID = l.ID, LastModificationDate = l.LastModificationDate, DateCreated = l.DateCreated,LetterStatus = new {ID = l.LetterStatusID.Value,NameInArabic = l.LetterStatus.NameInArabic,NameInEnglish = l.LetterStatus.NameInEnglish} })
                               ^^ without type__________________________________________________________________________________________________________^^ without type

あなたはこのエラーが発生するcomplex propertiesさえ、閉包の選択でnew keywordを追加しました

そのremoveClassTypes from newLinq to Entity ClassTypes from newキーワードLinq to Entityクエリにremoveする

それはSQL文に変換され、SqlServer上で実行されるためです

では、 いつselect closureでnew with typesを使用できselectか?

LINQ to Object (in memory collection)を扱っている場合に使用できます。

//opecations in tempList , LINQ to Entities; so we can not use class types in select only anonymous types are allowed
var tempList = dbQuery.Skip(10).Take(10).ToList();// this is list of <anonymous type> so we have to convert it so list of <letter>

//opecations in list , LINQ to Object; so we can use class types in select
list = tempList.Select(l => new Letter{ Title = l.Title, ID = l.ID, LastModificationDate = l.LastModificationDate, DateCreated = l.DateCreated, LetterStatus = new LetterStatus{ ID = l.LetterStatus.ID, NameInArabic = l.LetterStatus.NameInArabic, NameInEnglish = l.LetterStatus.NameInEnglish } }).ToList();
                                ^^^^^^ with type 

クエリ上でToListを実行した後、それがin memory collectionなったので、selectでnew ClassTypesを使用できます




多くの場合、変換は必要ありません。 厳密に型リストを作成する理由を考え、Webサービスや表示などのデータだけを必要とするかどうかを評価します。 タイプには関係ありません。 それを読んで、あなたが定義した匿名型で定義されたプロパティと同じであることを確認するだけでいいです。 これは、オプティマンのシナリオです。エンティティのすべてのフィールドが必要ないことが原因です。そのため、匿名型が存在します。

簡単な方法はこれを行うことです:

IEnumerable<object> list = dataContext.Table.Select(e => new { MyRequiredField = e.MyRequiredField}).AsEnumerable();