ไม่สามารถสร้างค่าคงที่ประเภทสนับสนุนเฉพาะประเภทดั้งเดิมหรือประเภทการแจงนับในบริบทนี้


164

ฉันได้รับข้อผิดพลาดนี้สำหรับข้อความค้นหาด้านล่าง

API.Models.PersonProtocolไม่สามารถสร้างค่าคงที่ของประเภท สนับสนุนชนิดดั้งเดิมหรือชนิดการแจงนับเท่านั้นในบริบทนี้

ppCombinedด้านล่างเป็นIEnumerableวัตถุของPersonProtocolTypeซึ่งถูกสร้างขึ้นโดย concat ของ 2 PersonProtocolรายการ

เหตุใดจึงล้มเหลว เราไม่สามารถใช้ LINQ JOINข้อภายในSELECTของJOIN?

var persons = db.Favorites
    .Where(x => x.userId == userId)
    .Join(db.Person, x => x.personId, y => y.personId, (x, y) =>
        new PersonDTO
        {
            personId = y.personId,
            addressId = y.addressId,                   
            favoriteId = x.favoriteId,
            personProtocol = (ICollection<PersonProtocol>) ppCombined
                .Where(a => a.personId == x.personId)
                .Select( b => new PersonProtocol()
                 {
                     personProtocolId = b.personProtocolId,
                     activateDt = b.activateDt,
                     personId = b.personId
                 })
        });


ที่เกี่ยวข้อง: ไม่สามารถสร้างค่าคงที่ - เพียงชนิดดั้งเดิม

คำตอบ:


232

สิ่งนี้ไม่สามารถใช้งานได้เนื่องจากppCombinedเป็นชุดของวัตถุในหน่วยความจำและคุณไม่สามารถเข้าร่วมชุดข้อมูลในฐานข้อมูลกับชุดข้อมูลอื่นที่อยู่ในหน่วยความจำ คุณสามารถลองแยกไอเท็มที่กรองแล้วpersonProtocolของppCombinedคอลเลกชันในหน่วยความจำหลังจากที่คุณได้รับคุณสมบัติอื่น ๆ จากฐานข้อมูล:

var persons = db.Favorites
    .Where(f => f.userId == userId)
    .Join(db.Person, f => f.personId, p => p.personId, (f, p) =>
        new // anonymous object
        {
            personId = p.personId,
            addressId = p.addressId,   
            favoriteId = f.favoriteId,
        })
    .AsEnumerable() // database query ends here, the rest is a query in memory
    .Select(x =>
        new PersonDTO
        {
            personId = x.personId,
            addressId = x.addressId,   
            favoriteId = x.favoriteId,
            personProtocol = ppCombined
                .Where(p => p.personId == x.personId)
                .Select(p => new PersonProtocol
                {
                    personProtocolId = p.personProtocolId,
                    activateDt = p.activateDt,
                    personId = p.personId
                })
                .ToList()
        });

10
ส่วนสำคัญสำหรับฉันเพิ่ม. AsEnumerable () // แบบสอบถามฐานข้อมูลสิ้นสุดลงที่นี่ส่วนที่เหลือเป็นข้อความค้นหาในหน่วยความจำ
Sameer Alibhai

2
@Slauma ดังนั้นถ้าฉันกังวลเกี่ยวกับประสิทธิภาพฉันควรหลีกเลี่ยงการทำเช่นนี้เพราะมันจะโหลดข้อมูลทั้งหมดในหน่วยความจำก่อนแล้วจึงทำการสืบค้น ฉันควรเขียน raw sql สำหรับสถานการณ์นี้หรือไม่?
Arvand

ดูเหมือน @Arvand มีจุดที่ดี หากคุณมีบันทึกจำนวนมากก่อนตัวกรองสิ่งนี้อาจทำให้ทรัพยากรหน่วยความจำที่เหลืออยู่มีจำนวนมาก
spadelives

5
@Slauma "วิธีนี้ใช้ไม่ได้เพราะ ppCombined เป็นชุดของวัตถุในหน่วยความจำและคุณไม่สามารถเข้าร่วมชุดข้อมูลในฐานข้อมูลด้วยชุดข้อมูลอื่นที่อยู่ในหน่วยความจำ" ฉันจะหาเอกสารเกี่ยวกับสิ่งนี้ได้ที่ไหน ฉันขาดความรู้เกี่ยวกับขีด จำกัด ของ EF จริงๆและเมื่อฉันพยายาม จำกัด ชุดผลลัพธ์ของแบบสอบถามเช่นนี้การไร้ความสามารถนี้ทำให้ตัวเองชัดเจนมากและทำให้ฉันช้าลง
Nomenator

1
ข้อมูลที่ดี ฉันกำลังเพิ่มข้อยกเว้นนี้ลงในรายการข้อความข้อยกเว้นที่เข้าใจง่ายน้อยที่สุดของฉัน มันสมเหตุสมผลแล้วหลังจากที่คุณเข้าใจว่าทำไมมันถึงเกิดขึ้น
DVK

2

ไม่รู้ว่ามีใครค้นหาสิ่งนี้หรือไม่ ผมมีปัญหาเหมือนกัน. เลือกในแบบสอบถามแล้วทำที่ไหน (หรือเข้าร่วม) และการใช้ตัวแปรเลือกแก้ปัญหาสำหรับฉัน (ปัญหาอยู่ในคอลเลกชัน "reintegraties" สำหรับฉัน)

query.Select(zv => new
            {
                zv,
                rId = zv.this.Reintegraties.FirstOrDefault().Id
            })
            .Where(x => !db.Taken.Any(t => t.HoortBijEntiteitId == x.rId
                                             && t.HoortBijEntiteitType == EntiteitType.Reintegratie
                                             && t.Type == TaakType))
            .Select(x => x.zv);

หวังว่านี่จะช่วยทุกคน


6
zv.this.Reintegraties.FirstOrDefault().Idศักยภาพ NullReferenceException

2

ในกรณีของฉันฉันสามารถแก้ไขปัญหาได้โดยทำสิ่งต่อไปนี้:

ฉันเปลี่ยนรหัสจากสิ่งนี้:

var r2 = db.Instances.Where(x => x.Player1 == inputViewModel.InstanceList.FirstOrDefault().Player2 && x.Player2 == inputViewModel.InstanceList.FirstOrDefault().Player1).ToList();

สำหรับสิ่งนี้:

var p1 = inputViewModel.InstanceList.FirstOrDefault().Player1;
var p2 = inputViewModel.InstanceList.FirstOrDefault().Player2;
var r1 = db.Instances.Where(x => x.Player1 == p1 && x.Player2 == p2).ToList();

สิ่งนี้ไม่ได้ผลสำหรับฉัน ในฐานะp1และp2เป็นทั้งในหน่วยความจำไม่ว่าจะมีการประกาศโดยไม่ระบุชื่อหรือชื่อตัวแปร
Rahat Zaman

2
ประเภทตัวแปรไม่ใช่ปัญหา ในกรณีของฉันเกิดข้อผิดพลาดเพราะทำ. FirstOrDefault () ภายในส่วนคำสั่ง Where
โคลิน

1

เป็นการเพิ่มที่คุ้มค่าเนื่องจากตัวอย่างรหัสของ OP ไม่ได้มีบริบทเพียงพอที่จะพิสูจน์เป็นอย่างอื่น แต่ฉันได้รับข้อผิดพลาดนี้เช่นกันในรหัสต่อไปนี้:

public RetailSale GetByRefersToRetailSaleId(Int32 refersToRetailSaleId)
{
    return GetQueryable()
        .FirstOrDefault(x => x.RefersToRetailSaleId.Equals(refersToRetailSaleId));
}

เห็นได้ชัดว่าฉันไม่สามารถใช้Int32.Equalsในบริบทนี้เพื่อเปรียบเทียบ Int32 กับ int ดั้งเดิม ฉันต้องเปลี่ยน (อย่างปลอดภัย) เป็น:

public RetailSale GetByRefersToRetailSaleId(Int32 refersToRetailSaleId)
{
    return GetQueryable()
      .FirstOrDefault(x => x.RefersToRetailSaleId == refersToRetailSaleId);
}

EF ยอมรับได้Equalsอย่างสมบูรณ์แบบ
Gert Arnold

0

เพียงเพิ่ม AsEnumerable () และ ToTo () เพื่อให้มีลักษณะเช่นนี้

db.Favorites
    .Where(x => x.userId == userId)
    .Join(db.Person, x => x.personId, y => y.personId, (x, y).ToList().AsEnumerable()

ToList().AsEnumerable()

0

ฉันมีปัญหานี้และสิ่งที่ฉันทำและแก้ไขปัญหาคือฉันใช้AsEnumerable()ก่อนที่จะเข้าร่วมข้อของฉัน นี่คือแบบสอบถามของฉัน:

List<AccountViewModel> selectedAccounts;

 using (ctx = SmallContext.GetInstance()) {
                var data = ctx.Transactions.
                    Include(x => x.Source).
                    Include(x => x.Relation).
                    AsEnumerable().
                    Join(selectedAccounts, x => x.Source.Id, y => y.Id, (x, y) => x).
                    GroupBy(x => new { Id = x.Relation.Id, Name = x.Relation.Name }).
                    ToList();
            }

ผมก็สงสัยว่าทำไมปัญหานี้เกิดขึ้นและตอนนี้ผมคิดว่ามันเป็นเพราะหลังจากที่คุณทำแบบสอบถามผ่านทางLINQผลที่ได้จะอยู่ในหน่วยความจำและไม่โหลดลงในวัตถุผมไม่ทราบว่าสิ่งที่รัฐที่มีแต่พวกเขาอยู่ในในบางฉันคิดว่ารัฐหัวต่อหัวเลี้ยว จากนั้นเมื่อคุณใช้AsEnumerable()หรือToList()ฯลฯ คุณกำลังวางวัตถุเหล่านั้นลงในวัตถุหน่วยความจำกายภาพและปัญหากำลังได้รับการแก้ไข

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