Linq เป็น EntityFramework DateTime


108

ในแอปพลิเคชันของฉันฉันกำลังใช้ Entity Framework

โต๊ะของฉัน

-Article
-period
-startDate

ฉันต้องการบันทึกที่ตรงกับ => DateTime.Now > startDate and (startDate + period) > DateTime.Now

ฉันลองใช้รหัสนี้ แต่ใช้งานได้แล้ว

Context.Article
    .Where(p => p.StartDate < DateTime.Now)
    .Where(p => p.StartDate.AddDays(p.Period) > DateTime.Now)

เมื่อฉันเรียกใช้รหัสของฉันข้อยกเว้นต่อไปนี้เกิดขึ้น

LINQ เป็นเอนทิตีไม่รู้จักเมธอด 'System.DateTime AddDays (Double)' และวิธีนี้ไม่สามารถแปลเป็นนิพจน์ร้านค้าได้


ประเภทคือperiodอะไร? AddDaysเป็นฟังก์ชันที่ไม่ถูกต้องหากเป็นไฟล์double.
Craig Stuntz

คำตอบ:


201

เมื่อใช้ LINQ กับ Entity Framework เพรดิเคตของคุณภายในประโยค Where จะถูกแปลเป็น SQL คุณได้รับข้อผิดพลาดนั้นเนื่องจากไม่มีการแปลเป็น SQL DateTime.Add()ที่สมเหตุสมผล

วิธีแก้ปัญหาอย่างรวดเร็วคือการอ่านผลลัพธ์ของคำสั่ง Where แรกในหน่วยความจำจากนั้นใช้ LINQ กับ Objects เพื่อสิ้นสุดการกรอง:

Context.Article.Where(p => p.StartDate < DateTime.Now)
               .ToList()
               .Where(p => p.StartDate.AddDays(p.Period) > DateTime.Now);

คุณยังสามารถลองใช้วิธีEntityFunctions.AddDays ได้หากคุณใช้. NET 4.0:

Context.Article.Where(p => p.StartDate < DateTime.Now)
               .Where(p => EntityFunctions.AddDays(p.StartDate, p.Period)
                   > DateTime.Now);

หมายเหตุ: ในตอนนี้มันEF 6System.Data.Entity.DbFunctions.AddDays


42
นี่เป็นการหลีกเลี่ยงปัญหาที่อันตรายจะเกิดอะไรขึ้นถ้า ToList () ส่งคืนข้อมูลจำนวนมาก
Stefan P.

7
ขอบคุณสำหรับ EntityFunctions เคล็ดลับ AddDays ฉันใช้ EF .net 4.0 แต่ฉันไม่รู้เกี่ยวกับ EntityFunctions จะตรวจสอบให้
Stefan P.

2
@SaeedAlg - ในตัวอย่างแรกจำเป็นต้องอ่านรายการในหน่วยความจำ ในตัวอย่างที่สองฉันเก็บคำสั่ง Where ไว้สองคำเพื่อให้ตรงกับรูปแบบเดิม แม้ว่าคุณจะบีบอัดข้อมูลทั้งสองลงใน Where clause เดียว Entity Framework ก็สร้าง Identity SQL ขึ้นมาดังนั้นจึงเป็นเรื่องของการอ่านง่าย
Justin Niessner

2
@ จัสตินนีสเนอร์ขอบคุณมากฉันพยายามทำอย่างนั้นเป็นเวลาสี่ชั่วโมงคุณช่วยชีวิตฉันได้ในไม่กี่วินาทีขอบคุณอีกครั้ง
Yucel

2
เมื่อให้วิธีการแก้ไขอย่างรวดเร็วกับ EF เราทุกคนควรหลีกเลี่ยงการใช้วิธี ToList และ ToArray การคำนวณวันที่ก่อนหน้านี้ทำได้รวดเร็วและเปรียบเทียบกับค่านั้นและทำงานในคิวรี EF โดยไม่ต้องสร้างอินสแตนซ์ผลลัพธ์ในหน่วยความจำ
Isaac Llopis

92

ฉันคิดว่านี่คือสิ่งที่คำตอบสุดท้ายที่พยายามแนะนำ แต่แทนที่จะพยายามเพิ่มวันใน p.startdat (สิ่งที่ไม่สามารถแปลงเป็นคำสั่ง sql) ทำไมไม่ทำบางสิ่งที่สามารถเทียบเท่ากับ sql:

var baselineDate = DateTime.Now.AddHours(-24);

something.Where(p => p.startdate >= baselineDate)

2
@ เอเดรียนคาร์ - อาจดีกว่าสำหรับกรณีการใช้งานนี้ แต่ไม่มากเท่าEntityFunctionsวิธีแก้ปัญหา ที่นี่ตัวถูกดำเนินการที่สองจะไม่ถูกเรียกจากเอนทิตีอื่นในแบบสอบถามและสามารถคำนวณได้ก่อนที่จะทำการสืบค้น หากพบตัวถูกดำเนินการทั้งสองใน db EntityFunctionsโซลูชันจะยังคงเหมาะสมในขณะที่คำตอบของการตอบกลับนี้จะไม่ทำงานอีกต่อไป
Frédéric

นี่เป็นทางออกที่ดีกว่าโซลูชันที่ระบุว่าเป็นคำตอบ การตอบกลับจาก Justin / คำตอบที่ทำเครื่องหมายไว้จะส่งคืนผลลัพธ์ที่ไม่จำเป็นจากฐานข้อมูล โซลูชันนี้จะส่งวันที่ใน SQL ซึ่งจะกรองและใช้ SQL เพื่อกรองข้อมูลซึ่งมีประสิทธิภาพมากกว่ามาก
พอล

3

วิธีการลบ 2 วันจาก DateTime ตอนนี้:

Context.Article
.Where(p => p.StartDate < DateTime.Now)
.Where(p => p.StartDate > DateTime.Now.Subtract(new TimeSpan(2, 0, 0, 0)))

พูดตามตรงฉันไม่แน่ใจว่าคุณพยายามทำอะไรอยู่ แต่อาจได้ผล


บทความจะเริ่มแสดงใน StartDate และสิ้นสุดหลังจาก x (period) วัน นี่คือสิ่งที่ฉันพยายามทำ โซลูชันที่สองของ Justin Niessner ทำงานได้ดีมากสำหรับสิ่งที่ฉันต้องการเห็น
Yucel

3

หากคุณต้องการให้นิพจน์ของคุณถูกแปลเป็น SQL คุณสามารถลองใช้

System.Data.Entity.Core.Objects.AddDays วิธีการ

จริงๆแล้วถูกทำเครื่องหมายว่าล้าสมัย แต่ใช้งานได้ ควรแทนที่ด้วย System.Data.Entity.DbFunctions.AddDays แต่หาไม่เจอ ...


สิ่งนี้เพิ่มอะไรมากไปกว่าคำตอบที่ยอมรับจาก 4 ปีก่อนหน้านี้!
Andrew Harris

@AndrewHarris คำตอบของฉันคือคำตอบเมื่อ 4 ปีที่แล้ว ในรุ่นแรกของคำตอบจะมี ToList (=> data materialization) อยู่ก่อน Where (ดูความคิดเห็นแรกของคำตอบ)
bubi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.