ไม่สนับสนุนสมาชิกประเภทที่ระบุ 'วันที่' ใน LINQ ถึง Entities Exception


105

ฉันได้รับข้อยกเว้นขณะใช้ข้อความต่อไปนี้

 DateTime result;
 if (!DateTime.TryParse(rule.data, out result))
     return jobdescriptions;
 if (result < new DateTime(1754, 1, 1)) // sql can't handle dates before 1-1-1753
     return jobdescriptions;
 return jobdescriptions.Where(j => j.JobDeadline.Date == Convert.ToDateTime(rule.data).Date );

ข้อยกเว้น

The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.

ฉันรู้ว่าข้อยกเว้นหมายถึงอะไร แต่ฉันไม่รู้วิธีกำจัด ความช่วยเหลือใด ๆ


นี่คือใน EF6 และต่ำกว่า EF .Dateสนับสนุนหลัก
Gert Arnold

คำตอบ:


102

LINQ เป็นเอนทิตีไม่สามารถแปลเมธอด. NET Date ส่วนใหญ่ (รวมถึงการแคสต์ที่คุณใช้) เป็น SQL เนื่องจากไม่มี SQL ที่เทียบเท่า

วิธีแก้ไขคือใช้เมธอด Date ภายนอกคำสั่ง LINQ แล้วส่งผ่านค่า ดูเหมือนว่า Convert ToDateTime (rule.data) วันที่ทำให้เกิดข้อผิดพลาด

การเรียกวันที่ในคุณสมบัติ DateTime ยังไม่สามารถแปลเป็น SQL ได้ดังนั้นวิธีแก้ปัญหาคือการเปรียบเทียบคุณสมบัติ. ปี. เดือนและ. วันซึ่งสามารถแปลเป็น LINQ ได้เนื่องจากเป็นเพียงจำนวนเต็ม

var ruleDate = Convert.ToDateTime(rule.data).Date;
return jobdescriptions.Where(j => j.Deadline.Year == ruleDate.Year 
                       && j.Deadline.Month == ruleDate.Month 
                       && j.Deadline.Day == ruleDate.Day);

6
แล้ว j => j.JobDeadline.Dateล่ะ?
เนบิวลา

1
Date เป็นคุณสมบัติบน JobDeadline หรือไม่ สิ่งนี้ไม่ควรทำให้เกิดข้อผิดพลาดด้วยตัวเอง - อาจเป็นข้อขัดแย้งในการตั้งชื่อ (แต่ไม่แน่ใจในเรื่องนี้) หากบรรทัดยังคงทำให้เกิดข้อผิดพลาดให้เปลี่ยนชื่อเป็น DeadlineDate หรือคล้ายกัน
ยูโด

1
วันที่เป็นคุณสมบัติใน JobDeadline JobDeadline เป็นประเภท DateTime ที่ฉันต้องการแยก Date
เนบิวลา

จากนั้นในการทำงานนี้ภายใน LINQ คุณจะต้องเปรียบเทียบคุณสมบัติ JobDeadline เช่น j.JobDeadline> ruleDate สิ่งนี้ต้องการการทดสอบเล็กน้อย แต่สามารถใช้งานได้ หรือเปรียบเทียบคุณสมบัติสามประการของ. เดือน. วันและ. ปี (j.Deadline.Year == ruleDate.Year && j j j.Deadline.Month == ruleDate.Month && j.Deadline.Day == ruleDate.Day) ไม่หรูหรา แต่ใช้งานได้เนื่องจากเป็นจำนวนเต็มเท่านั้น
ยูโด

อืม. ความคิดนี้ได้ผล สกปรก แต่ใช้งานได้ ถ้าคุณเขียนเป็นคำตอบฉันสามารถทำเครื่องหมายว่าถูกต้อง
เนบิวลา

230

คุณสามารถใช้วิธีTruncateTimeของEntityFunctionsเพื่อให้ได้การแปลDateคุณสมบัติเป็น SQL ที่ถูกต้อง:

using System.Data.Objects; // you need this namespace for EntityFunctions

// ...

DateTime ruleData = Convert.ToDateTime(rule.data).Date;
return jobdescriptions
    .Where(j => EntityFunctions.TruncateTime(j.JobDeadline) == ruleData);


อัปเดต: EntityFunctionsเลิกใช้งานแล้วใน EF6 ใช้DbFunctions.TruncateTime


ฉันสังเกตเห็นว่าruleDataเป็นDateTimeประเภทและj.JobDeadlineมีการตัดทอนเวลา ไม่รู้สึกถูกต้อง ไม่ได้รับข้อยกเว้น แต่ไม่ได้รับผลที่คาดหวังเช่นกัน
เนบิวลา

@aneal: มันกลับระเบียนทั้งหมดที่JobDeadlineมีเหมือนกันวันเป็นrule.dataเรื่องสิ่งที่ไม่มีช่วงเวลาของวัน นั่นไม่ใช่สิ่งที่คุณต้องการบรรลุจากคำถามของคุณใช่หรือไม่? ทำไมถึงไม่รู้สึก?
Slauma

1
+1 และฉันเห็นด้วยกับข้างต้นเป็นคำตอบที่ดีกว่าแน่นอนสำหรับการใช้งาน 99%
jim tollan

26
โปรดทราบว่าEntityFunctionsเลิกใช้แล้วใน EF6 ตอนนี้คุณควรใช้DbFunctionsไฟล์.
Julien N

2
Namespace สำหรับ DbFunctions ใน> EF6 คือSystem.Data.Entity: msdn.microsoft.com/en-us/library/Dn220142(v=VS.113).aspx
GraehamF


9

"EntityFunctions.TruncateTime" หรือ "DbFunctions.TruncateTime" ใน ef6 ใช้งานได้ แต่มีปัญหาด้านประสิทธิภาพใน Big Data

ฉันคิดว่าวิธีที่ดีที่สุดคือทำตัวแบบนี้:

DateTime ruleDate = Convert.ToDateTime(rule.data);

DateTime  startDate = SearchDate.Date;

DateTime  endDate = SearchDate.Date.AddDay(1);

return jobdescriptions.Where(j.Deadline >= startDate 
                       && j.Deadline < endDate );

จะดีกว่าการใช้ส่วนของวันที่ถึง เนื่องจากคิวรีทำงานได้เร็วขึ้นในข้อมูลขนาดใหญ่


+1 สำหรับคำตอบนี้ EntityFunctions.TruncateTime(แทนที่ด้วยในภายหลังDbFunctions.TruncateTime) ถูกนำไปใช้โดยการแปลงเป็น SQL โดยที่ datetime ถูกแปลงเป็นสตริงและถูกตัดทอน สิ่งนี้ทำให้การสืบค้นทำงานช้าลงอย่างมากตามสัดส่วนของจำนวนระเบียนที่ประมวลผล
urig


1

ความหมายคือ LINQ เป็น SQL ไม่ทราบวิธีเปลี่ยนDateคุณสมบัติให้เป็นนิพจน์ SQL เนื่องจากDateคุณสมบัติของDateTimeโครงสร้างไม่มีอะนาล็อกใน SQL



0

ฉันมีปัญหาเดียวกัน แต่ฉันทำงานกับ DateTime-Ranges วิธีแก้ปัญหาของฉันคือจัดการเวลาเริ่มต้น (พร้อมวันที่ใดก็ได้) เป็น 00:00:00 และเวลาสิ้นสุดเป็น 23:59:59 น. ดังนั้นฉันต้องไม่แปลง DateTime เป็น Date อีกต่อไป แต่จะยังคงเป็น DateTime

หากคุณมี DateTime เพียงวันเดียวคุณยังสามารถตั้งเวลาเริ่มต้น (พร้อมวันที่ใดก็ได้) เป็น 00:00:00 และเวลาสิ้นสุดเป็น 23:59:59 น. จากนั้นค้นหาราวกับว่าเป็นช่วงเวลา

var from = this.setStartTime(yourDateTime);
var to = this.setEndTime(yourDateTime);

yourFilter = yourFilter.And(f => f.YourDateTime.Value >= from && f.YourDateTime.Value <= to);

คุณสามารถทำได้ด้วย DateTime-Range:

var from = this.setStartTime(yourStartDateTime);
var to = this.setEndTime(yourEndDateTime);

yourFilter = yourFilter.And(f => f.YourDateTime.Value >= from && f.YourDateTime.Value <= to);

0

คุณจะได้รับ Enum เช่น:

DateTime todayDate = DateTime.Now.Date; var check = db.tableName.AsEnumerable().Select(x => new
        {
            Date = x.TodayDate.Date
        }).Where(x => x.Date == todayDate).FirstOrDefault();

นี่เป็นการแจกแจงเนื้อหาทั้งหมดของตารางอย่างมีประสิทธิภาพล่วงหน้าเพื่อที่จะใช้ตัวกรองวันที่ ... ดูเหมือนจะเป็นความคิดที่แย่มาก !
Javier Rapoport

0

ดังที่หลายคนชี้ให้เห็นที่นี่การใช้ฟังก์ชัน TruncateTime นั้นช้า

ตัวเลือกที่ง่ายที่สุดหากทำได้คือใช้ EF Core มันสามารถทำได้ หากคุณทำไม่ได้ทางเลือกอื่นที่ดีกว่าในการตัดทอนคืออย่าเปลี่ยนฟิลด์ที่สืบค้นเลย แต่แก้ไขขอบเขต หากคุณกำลังทำแบบสอบถามประเภท 'ระหว่าง' ปกติโดยที่ขอบเขตล่างและบนเป็นทางเลือกสิ่งต่อไปนี้จะทำเคล็ดลับ

    public Expression<Func<PurchaseOrder, bool>> GetDateFilter(DateTime? StartDate, DateTime? EndDate)
    {
        var dtMinDate = (StartDate ?? SqlDateTime.MinValue.Value).Date;
        var dtMaxDate = (EndDate == null || EndDate.Value == SqlDateTime.MaxValue.Value) ? SqlDateTime.MaxValue.Value : EndDate.Value.Date.AddDays(1);
        return x => x.PoDate != null && x.PoDate.Value >= dtMinDate && x.PoDate.Value < dtMaxDate;
    }

โดยพื้นฐานแล้วแทนที่จะตัดแต่ง PoDate กลับไปเป็นเพียงส่วนวันที่เราจะเพิ่มขอบเขตคิวรีด้านบนและผู้ใช้ <แทน <=

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.