web-dev-qa-db-ja.com

LINQ to Entitiesがメソッド 'System.String ToString()を認識しないのはなぜですか?

MVC3 Webアプリケーション内でエラーを取得しています。 LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression.

クエリからEFを使用して値を取得しようとすると:

public class DataRepository
    {
        public mydataEntities1 dbContext = new mydataEntities1();

        public List<SelectListItem> GetPricingSecurityID()
        {
        var pricingSecurityID = (from m in dbContext.Reporting_DailyNAV_Pricing
                                     select new SelectListItem
                                         {
                                                Text = m.PricingSecurityID.ToString(),
                                                Value = m.PricingSecurityID.ToString()
                                         });

        return pricingSecurityID.ToList();
        }
    }
30
Neo

これはSQLに変換できません。理論上は可能ですが、実装されていません。

結果が得られたら、投影を実行するだけです。

var pricingSecurityID = (from m in dbContext.Reporting_DailyNAV_Pricing
                                     select m.PricingSecurityID).AsEnumerable()
    .Select(x => new SelectListItem{ Text = x.ToString(), Value = x.ToString() });
54
Jay

すでに文字列である場合、最初にToStringを呼び出すのはなぜですか?翻訳は無意味なので、LINQ to Entitiesに含まれていなかったと思います。選択句を次のように変更します。

select new SelectListItem
{
    Text = m.PricingSecurityID,
    Value = m.PricingSecurityID
}

本当に LINQ to Entitiesでサポートされていないことを行う必要がある場合は、AsEnumerableを使用してデータベースクエリからインプロセスに移行します。

public List<SelectListItem> GetPricingSecurityID()
{
    return dbContext.Reporting_DailyNAV_Pricing
                    .Select(m => m.PricingSecurityID)
                    .AsEnumerable() // Rest of query is local
                    // Add calls to ToString() if you really need them...
                    .Select(id => new SelectListItem { Text = id, Value = id })
                    .ToList();
}

ところで、私もジェイソンの異議に同意します。他の場所でレンダリングされるList<string>を返す方が良いでしょう。

また、just単一のselect句またはwhere句のみを使用する場合、クエリ式は実際にはあまり追加しないことに注意してください-LINQの呼び出し特に、クエリ式でare n'tがサポートされているメソッド(ToListなど)を呼び出したい場合は、拡張メソッドをすっきりさせることができます。

17
Jon Skeet

これはどう。この例では、dbのVDNフィールドとSkillフィールドの両方が整数です。両方のフィールドからの一致を探しているので、2つの比較があります。

これを含める:

using System.Data.Objects.SqlClient; // needed to convert numbers to strings for linq

数値を比較するときは次のようにします。

        // Search Code
            if (!String.IsNullOrEmpty(searchString))
            {
                depts = depts.Where(d => SqlFunctions.StringConvert((double)d.VDN).Contains(searchString.ToUpper())
                || SqlFunctions.StringConvert((double)d.Skill).Contains(searchString.ToUpper()));
            }
        // End Search Code

Workie。

4
C Cartheuser

SQLに変換しようとしているため、変換できないためです。 ToStringへの呼び出しを中止し、呼び出し元に戻る前に投影を行います。したがって、select句を次のように置き換えます

select m.PricingSecurityID

そして言う

return pricingSecurityID
           .AsEnumerable()
           .Select(x => x.ToString())
           .Select(x => new SelectListItem { Text = x, Value = x })
           .ToList();

また、UIの懸念とデータクエリの懸念が混在していることに注意してください。これは一般的に悪い習慣です。実際には、IDのリストを返すだけで、コードのUI部分が正しい形式に改ざんされるのを心配する必要があります。

4
jason

悲しいことに、EFは.ToString()の変換方法を認識していません。埋め込み関数SqlFunctions.StringConvertを使用する必要があります: http://msdn.Microsoft.com/en-us/library/dd466292.aspx また、intにはオーバーロードがないため、型キャストを2倍にする必要があります:-(

var vendors = 
   from v in Vendors  
   select new
   {             
       Code = SqlFunctions.StringConvert((double)v.VendorId)
   }; 
3
Muhammad Alaa

私はこの質問に答えていることを理解しており、AsEnumerable()を使用することが道であることに同意します。ただし、このエラーを解決するためにAsEnumerable()が非効率的に使用される場合によく遭遇する一般的なシナリオを強調したいと思います。

From リレーショナルデータの.NET言語統合クエリ

AsEnumerable()演算子は、ToList()やToArray()とは異なり、クエリを実行しません。まだ延期されています。 AsEnumerable()演算子は、クエリの静的な型付けを変更するだけで、IQueryableをIEnumerableに変換し、コンパイラがクエリの残りをローカルで実行されたものとして扱うようにします。

参考文献

  1. LINQ to SQLを誤解していますか?AsEnumerable()?
  2. LINQ to SQLの.AsEnumerable()を理解する

非効率な方法

IEnumerable<InvoiceDTO> inefficientEnumerable = 
     (from a in db.Invoices
     where a.Practice_Key == practiceKey.FirstOrDefault()
     select a
     ).AsEnumerable().
     Select(x => new InvoiceDTO
                             {
                                 InvoiceID = x.InvoiceID,
                                 PracticeShortName = x.Dim_Practice.Short_Name,
                                 InvoiceDate = x.InvoiceDate,
                                 InvoiceTotal = x.InvoiceAmount,
                                 IsApproved = x.IsApproved,
                                 InvoiceStatus = (
                                                  x.IsApproved == null ? "Pending" :
                                                  x.IsApproved == true ? "Approved" :
                                                  x.IsApproved == false ? "Rejected" : "Unknown"
                                                ),
                                 InvoicePeriodStartDateText = x.InvoicePeriodStart.ToShortDateString(),
                                 InvoicePeriodEndDateText = x.InvoicePeriodEnd.ToShortDateString(),
                                 InvoicePeriodStartDate = x.InvoicePeriodStart,
                                 InvoicePeriodEndDate = x.InvoicePeriodEnd
                             }
                             );

            invoices = inefficientEnumerable.ToList();

ここでは、AsEnumerableがテーブル全体に使用されます。必要ではありませんが、すべての列が選択されています。

より良い方法

 IQueryable<InvoiceDTO> invoicesQuery = 
   (from a in db.Invoices
   where a.Practice_Key == practiceKey.FirstOrDefault()
   select new InvoiceDTO
            {
             InvoiceID = a.InvoiceID,
             PracticeShortName = a.Dim_Practice.Short_Name,
             InvoiceDate = a.InvoiceDate,
             InvoiceTotal = a.InvoiceAmount,
             IsApproved = a.IsApproved,
             InvoiceStatus = (
                               a.IsApproved == null ? "Pending" :
                               a.IsApproved == true ? "Approved" :
                               a.IsApproved == false ? "Rejected" :"Unknown"
                               ),
             InvoicePeriodStartDate = a.InvoicePeriodStart,
             InvoicePeriodEndDate = a.InvoicePeriodEnd
          });


          IEnumerable<InvoiceDTO> betterEnumerable = invoicesQuery.AsEnumerable().
          Select(x => new InvoiceDTO
                                 {
                                     InvoiceID = x.InvoiceID,
                                     PracticeShortName = x.PracticeShortName,
                                     InvoiceDate = x.InvoiceDate,
                                     InvoiceTotal = x.InvoiceTotal,
                                     IsApproved = x.IsApproved,
                                     InvoiceStatus = x.InvoiceStatus,
                                     InvoicePeriodStartDateText = x.InvoicePeriodStartDate.ToShortDateString(),
                                     InvoicePeriodEndDateText = x.InvoicePeriodEndDate.ToShortDateString(),
                                     InvoicePeriodStartDate = x.InvoicePeriodStartDate,
                                     InvoicePeriodEndDate = x.InvoicePeriodEndDate
                                 }
                                 );
1
Lijo

VB.NETを使用してこれを試してください。重要な点は、回答で説明されているように、AsEnumerableの結果を取得する必要があることです。

Dim _EventsDaysResult = From ED In TAdbContext.EventPolicies.AsEnumerable
                                    Where ED.EventID = EID
                                    Select New With {ED.EventID, 
                                    .DayInfo = 
                                    ED.EventDay.GetValueOrDefault.ToShortDateString & " ( " & ED.EventDayTitle & " ) "}
0
Waseem Tahir