Saya memiliki kueri linq ini:
private void GetReceivedInvoiceTasks(User user, List<Task> tasks)
{
var areaIds = user.Areas.Select(x => x.AreaId).ToArray();
var taskList = from i in _db.Invoices
join a in _db.Areas on i.AreaId equals a.AreaId
where i.Status == InvoiceStatuses.Received && areaIds.Contains(a.AreaId)
select new Task {
LinkText = string.Format(Invoice {0} has been received from {1}, i.InvoiceNumber, i.Organisation.Name),
Link = Views.Edit
};
}
Ini memiliki masalah. Saya mencoba membuat tugas. Untuk setiap tugas baru ketika saya menyetel teks tautan ke string konstan seperti "Halo" tidak apa-apa. Namun di atas saya mencoba membangun teks tautan properti menggunakan properti faktur.
Saya mendapatkan kesalahan ini:
base {System.SystemException} = {"LINQ ke Entitas tidak mengenali metode metode 'System.String Format (System.String, System.Object, System.Object)', dan metode ini tidak dapat diterjemahkan ke dalam ekspresi penyimpanan." }
Ada yang tahu kenapa? Adakah yang tahu cara alternatif melakukan ini untuk membuatnya berhasil?
linq
entity-framework
linq-to-entities
AnonyMouse
sumber
sumber
Jawaban:
Kerangka Kerja Entitas mencoba menjalankan proyeksi Anda di sisi SQL, di mana tidak ada yang setara dengan
string.Format
. GunakanAsEnumerable()
untuk memaksa evaluasi bagian itu dengan Linq ke Objek.Berdasarkan jawaban sebelumnya yang saya berikan kepada Anda, saya akan menyusun ulang kueri Anda seperti ini:
int statusReceived = (int)InvoiceStatuses.Received; var areaIds = user.Areas.Select(x=> x.AreaId).ToArray(); var taskList = (from i in _db.Invoices where i.Status == statusReceived && areaIds.Contains(i.AreaId) select i) .AsEnumerable() .Select( x => new Task() { LinkText = string.Format("Invoice {0} has been received from {1}", x.InvoiceNumber, x.Organisation.Name), Link = Views.Edit });
Juga saya melihat Anda menggunakan entitas terkait di query (
Organisation.Name
) pastikan Anda menambahkan yang tepatInclude
ke kueri Anda, atau secara khusus mewujudkan properti tersebut untuk digunakan nanti, yaitu:var taskList = (from i in _db.Invoices where i.Status == statusReceived && areaIds.Contains(i.AreaId) select new { i.InvoiceNumber, OrganisationName = i.Organisation.Name}) .AsEnumerable() .Select( x => new Task() { LinkText = string.Format("Invoice {0} has been received from {1}", x.InvoiceNumber, x.OrganisationName), Link = Views.Edit });
sumber
IQueryable
berasal dariIEnumerable
, kemiripan utamanya adalah ketika Anda membuat kueri, kueri tersebut dikirim ke mesin database dalam bahasanya, saat yang tepat adalah saat Anda memberi tahu C # untuk menangani data di server (bukan sisi klien) atau memberi tahu SQL untuk menangani data.Jadi pada dasarnya ketika Anda mengatakan
IEnumerable.ToString()
, C # mendapatkan pengumpulan data dan panggilanToString()
pada objek. Tetapi ketika Anda mengatakanIQueryable.ToString()
C # memberitahu SQL untuk memanggilToString()
objek tetapi tidak ada metode seperti itu dalam SQL.Kekurangannya adalah ketika Anda menangani data di C #, seluruh koleksi yang Anda cari harus dibangun di memori sebelum C # menerapkan filter.
Cara paling efisien untuk melakukannya adalah dengan membuat kueri seperti
IQueryable
semua filter yang bisa Anda terapkan.Dan kemudian membangunnya di memori dan membuat format data di C #.
IQueryable<Customer> dataQuery = Customers.Where(c => c.ID < 100 && c.ZIP == 12345 && c.Name == "John Doe"); var inMemCollection = dataQuery.AsEnumerable().Select(c => new { c.ID c.Name, c.ZIP, c.DateRegisterred.ToString("dd,MMM,yyyy") });
sumber
Sementara SQL tidak tahu apa yang harus dilakukan dengan
string.Format
itu, ia dapat melakukan penggabungan string.Jika Anda menjalankan kode berikut maka Anda harus mendapatkan data yang Anda cari.
var taskList = from i in _db.Invoices join a in _db.Areas on i.AreaId equals a.AreaId where i.Status == InvoiceStatuses.Received && areaIds.Contains(a.AreaId) select new Task { LinkText = "Invoice " + i.InvoiceNumber + "has been received from " + i.Organisation.Name), Link = Views.Edit };
Setelah Anda benar-benar melakukan kueri, ini seharusnya sedikit lebih cepat daripada menggunakan
AsEnumerable
(setidaknya itulah yang saya temukan di kode saya sendiri setelah mengalami kesalahan asli yang sama seperti Anda). Jika Anda melakukan sesuatu yang lebih kompleks dengan C # maka Anda masih perlu menggunakannyaAsEnumerable
.sumber
AsEnumerable()
dapat jauh lebih efisien. HindariAsEnumerable()
danToList()
sampai Anda benar-benar ingin membawa semua hasil ke dalam ingatan.