2009-08-12 17 views
9

私はthis questionで始まりました。私はthereと答えました。そして今、もっと根本的な質問をしています。私はこれまで、クエリを簡素化しました:Linq "式をSQLに変換できなかったため、ローカル式として扱うことができませんでした。"

var q = from ent in LinqUtils.GetTable<Entity>() 
     from tel in ent.Telephones.DefaultIfEmpty() 
     select new { 
      Name = ent.FormattedName, 
      Tel = tel != null ? tel.FormattedNumber : "" // this is what causes the error 
     }; 

tel.FormattedNumberはきちんとフォーマットされた文字列にNumberExtensionフィールドを組み合わせたプロパティです。

System.InvalidOperationException: Could not translate expression 'Table(Entity).SelectMany(ent => ent.Telephones.DefaultIfEmpty(), (ent, tel) => new <>f__AnonymousType0`2(Name = ent.FormattedName, Tel = IIF((tel != null), tel.FormattedNumber, "")))' into SQL and could not treat it as a local expression. 

を私はNumberFormattedNumberへの単なるは、すべてが正常に動作しますから、上記の基準を変更した場合:そして、ここでの結果エラーがあります。

しかし、私はフォーマットされた数字を私のリストにうまく表示したいと思います。そうするためのきれいな、きれいな方法として何をお勧めしますか?

答えて

11

エンティティでAsEnumerableを使用することはできますが、使用しない場合でもすべての列を戻すことができます。おそらく代わりのようなもの:

FormatNumberは、おそらくあなたの他の(プロパティ)コードから再利用2を取り、それらをマージし、いくつかの方法で、ある
var q1 = from ent in LinqUtils.GetTable<Entity>() 
     from tel in ent.Telephones.DefaultIfEmpty() 
     select new { 
      Name = ent.FormattedName, 
      Number = (tel == null ? null : ent.Number), 
      Extension = (tel == null ? null : ent.Extension) 
     }; 

var q2 = from row in q1.AsEnumerable() 
     select new { 
      row.Name, 
      FormattedNumber = FormatNumber(row.Number, row.Extension) 
     }; 

LINQ-to-SQLでは、データベース内の書式設定を行うデータコンテキストでUDFを公開することもできます。わずかに異なる例:

var qry = from cust in ctx.Customers // and tel 
      select new { 
       cust.Name, 
       FormattedNumber = ctx.FormatNumber(tel.Number, tel.Extension) 
      }; 

(データベースで作業を行うであろう。それは良いアイデア;-pであるかどうか)

1

@Marc Gravellは答えに私を打つも、信用へさまざまな回答者this question私は正しいトラックに私を入れた。

私はそうのように、多くのマークの最初の提案のようにそれをやった:

var q1 = from ent in LinqUtils.GetTable<Entity>() 
     from tel in ent.Telephones.DefaultIfEmpty() 
     select new { ent, tel }; 
var q2 = from q in q1.AsEnumerable() 
     select new { 
      Name = q.ent.FormattedName, 
      Tel = q.tel != null ? q.tel.FormattedNumber : "" 
     }; 

そして、それはそれをやりました! ありがとう、すべて!

3

実際に表現したいフィールドを表現し、中間層のオブジェクトに配置し、補助関数を使用して後者を修正するのが良い方法です。

LINQ用のSQLテーブルを表すクラスがDTOクラスであることが分かっているかどうかはわかりません.LINQ-SQLトランスレータで使用される文法を定義しています。 SQLテーブルにマップされていないDTOにプロパティをインジェクトすることは、サポートされていません。属性は文法を定義し、それによって定義されていないものは表現変換プログラムには存在しません。

from句で指定されたエンティティはオブジェクトではなく、フェッチされる実際のテーブルフィールドのスペルを助けるために使用される単なるシンボルです。 selectで明示的に指定されていないフィールドは、フェッチされないフィールドです - 少なくともトランスレータの目標ですが、いくつか伝える必要があるかもしれません。たとえば、そのent.FormattedNameが宣言されていない場合、それはスリップであり、後者を爆発させる可能性があります。

したがって、DTOクラスに注入されたFormattedNumberプロパティは、文法にも存在しません。 「計算されたフィールド」ではありません。その用語は厳密にはSQLテーブル定義のためのものであり、それがあればそれはDTOの文法に含まれます。エラーは非常に正確に "ローカル表現" - 非常に限られた範囲と言いました。

あなたはレコード全体のフェッチtrigerかもしれない全体の「TEL」の静的関数呼び出しのネストされたラムダ式で、それをごまかすために試みることができる - または別の例外をスローします。翻訳者ではありません

他のLINQ-sは、リラックスしたルールを持つことができます。 LINQ-SQLは、非常に厳しいまたは非常に遅いのいずれかである必要があり、それが

:-)既に十分に遅いです
関連する問題