ลำดับมีองค์ประกอบมากกว่าหนึ่งรายการ


111

ฉันมีปัญหาในการดึงรายการประเภท "RhsTruck" ผ่าน Linq และนำไปแสดง

RhsTruck มีคุณสมบัติ Make, Model, Serial และอื่น ๆ ... RhsCustomer มีคุณสมบัติ CustomerName, CustomerAddress, ฯลฯ ...

ฉันได้รับข้อผิดพลาด "ลำดับมีองค์ประกอบมากกว่าหนึ่งรายการ" ความคิดใด ๆ ? ฉันเข้าใกล้ผิดทางหรือเปล่า?

public RhsCustomer GetCustomer(string customerNumber)
{
    using (RhsEbsDataContext context = new RhsEbsDataContext() )
    {
        RhsCustomer rc = (from x in context.custmasts
                          where x.kcustnum == customerNumber
                          select new RhsCustomer()
                        {
                            CustomerName = x.custname,
                            CustomerAddress = x.custadd + ", " + x.custcity
                            CustomerPhone = x.custphone,
                            CustomerFax = x.custfax
                        }).SingleOrDefault();
        return rc;
    }
}

public List<RhsTruck> GetEquipmentOwned(RhsCustomer cust)
{
    using (RhsEbsDataContext context = new RhsEbsDataContext())
    {
        var trucks = (from m in context.mkpops
                      join c in context.custmasts
                        on m.kcustnum equals c.kcustnum
                      where m.kcustnum == cust.CustomerNumber
                      select new RhsTruck
                    {
                        Make = m.kmfg,
                        Model = m.kmodel,
                        Serial = m.kserialnum,
                        EquipID = m.kserialno1,
                        IsRental = false
                    }).ToList();
        return trucks;
    }
}

protected void Page_Load(object sender, EventArgs e)
{
    string testCustNum = Page.Request.QueryString["custnum"].ToString();

    RhsCustomerRepository rcrep = new RhsCustomerRepository();
    RhsCustomer rc = rcrep.GetCustomer(testCustNum);
    List<RhsTruck> trucks = rcrep.GetEquipmentOwned(rc);

    // I want to display the List into a Gridview w/auto-generated columns
    GridViewTrucks.DataSource = trucks;
    GridViewTrucks.DataBind();   
}

1
ใช้take <>เช่นเดียวกับฟังก์ชันการรวมSQL Top ().Take(1).SingleOrDefault();
Thein

คำตอบ:


255

SingleOrDefaultปัญหาคือว่าคุณกำลังใช้ วิธีนี้จะสำเร็จก็ต่อเมื่อคอลเล็กชันมีองค์ประกอบ 0 หรือ 1 เท่านั้น ฉันเชื่อว่าคุณกำลังมองหาFirstOrDefaultสิ่งที่จะประสบความสำเร็จไม่ว่าจะมีกี่องค์ประกอบในคอลเลกชันก็ตาม


8
คาลวินในกรณีนี้คุณควรยอมรับคำตอบนี้เป็นวิธีแก้ปัญหา
เดยันมิลิซิช

24
-1 "ปัญหาคือคุณกำลังใช้ SingleOrDefault" - จากสิ่งที่ฉันรวบรวมได้ OP กำลังมองหารหัสลูกค้าซึ่ง (ฉันคิดว่า) ควรจะไม่ซ้ำกันดังนั้นจึงSingleOrDefaultเหมาะสมกว่าFirstOrDefaultจริงๆ นอกจากนี้สิ่งนี้ทำให้เกิดปัญหาที่ร้ายแรงขึ้นกับการออกแบบฐานข้อมูลของ OP เนื่องจากแสดงให้เห็นว่าสามารถเพิ่มลูกค้า 2 รายที่มี ID เดียวกันได้!
เจมส์

27
@ เจมส์ OP ระบุว่าคำตอบของฉันถูกต้องและข้อยกเว้นระบุอย่างชัดเจนว่าคอลเลกชันมีองค์ประกอบมากกว่าหนึ่งรายการที่ป้องกันไม่ให้SingleOrDefaultใช้งานได้ จริงอาจเป็นไปได้ที่จะมีการออกแบบฐานข้อมูลที่ดีกว่าที่นี่ แต่ดูเหมือนว่าเหมาะสมกว่าในฐานะความคิดเห็นเกี่ยวกับ OP ไม่ใช่ -1 สำหรับคำตอบ
JaredPar

9
IMO ปัญหาพื้นฐานคือการออกแบบฐานข้อมูลในที่สุดเนื่องจากแสดงให้เห็นว่าสามารถเพิ่มรหัสลูกค้าที่ไม่ซ้ำกัน 2 รหัสลงในฐานข้อมูลได้ SingleOrDefaultกำลังทำให้เกิดข้อยกเว้นเนื่องจากมีความไม่สอดคล้องกันระหว่างสิ่งที่วิธีการคาดหวังและสิ่งที่กำลังค้นหา ดังนั้นแม้ว่าคำตอบของคุณจะหยุดข้อยกเว้น แต่สำหรับฉันแล้วมันไม่ได้ช่วยแก้ปัญหาได้จริง แต่เป็นการ์ด "ออกจากคุกฟรี" มากกว่าด้วยเหตุนี้ -1
เจมส์

2
นี่เป็นการเข้าใจผิด! การใช้งานSingleOrDefaultจะตกอยู่ในเวลาที่คุณคาดว่าคอลเลกชันจะมี 0 หรือ 1 รายการและคุณต้องการตรวจสอบสิ่งนี้เกิดขึ้นทุกครั้ง ...
Achilles

24

SingleOrDefaultวิธีการพ่นExceptionถ้ามีมากกว่าหนึ่งองค์ประกอบในลำดับ

เห็นได้ชัดว่าข้อความค้นหาของคุณGetCustomerกำลังค้นหารายการที่ตรงกันมากกว่าหนึ่งรายการ ดังนั้นคุณจะต้องปรับแต่งคำถามของคุณหรือโดยส่วนใหญ่แล้วคือตรวจสอบข้อมูลของคุณเพื่อดูว่าเหตุใดคุณจึงได้รับผลลัพธ์หลายรายการสำหรับหมายเลขลูกค้าที่ระบุ


5
Use FirstOrDefault insted of SingleOrDefault..

SingleOrDefault ส่งคืนองค์ประกอบ SINGLE หรือ null หากไม่พบองค์ประกอบ หากพบ 2 องค์ประกอบใน Enumerable ของคุณมันจะแสดงข้อยกเว้นที่คุณเห็น

FirstOrDefault ส่งคืนองค์ประกอบ FIRST ที่พบหรือเป็นโมฆะหากไม่พบองค์ประกอบ ดังนั้นหากมี 2 องค์ประกอบที่ตรงกับเพรดิเคตของคุณองค์ประกอบที่สองจะถูกละเว้น

   public int GetPackage(int id,int emp)
           {
             int getpackages=Convert.ToInt32(EmployerSubscriptionPackage.GetAllData().Where(x
   => x.SubscriptionPackageID ==`enter code here` id && x.EmployerID==emp ).FirstOrDefault().ID);
               return getpackages;
           }

 1. var EmployerId = Convert.ToInt32(Session["EmployerId"]);
               var getpackage = GetPackage(employerSubscription.ID, EmployerId);

1

FYI คุณยังสามารถรับข้อผิดพลาดนี้ได้หาก EF Migrations พยายามรันโดยไม่ได้กำหนดค่า Db ไว้ตัวอย่างเช่นใน Test Project

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


0

ดังที่ @Mehmet ชี้ให้เห็นหากผลลัพธ์ของคุณส่งคืนมากกว่า 1 ครั้งคุณต้องตรวจสอบข้อมูลของคุณเนื่องจากฉันสงสัยว่ามันไม่ได้เกิดจากการออกแบบที่คุณมีลูกค้าแชร์หมายเลขที่กำหนดเอง

แต่ในประเด็นนี้ฉันต้องการให้ภาพรวมคร่าวๆ

//success on 0 or 1 in the list, returns dafault() of whats in the list if 0
list.SingleOrDefault();
//success on 1 and only 1 in the list
list.Single();

//success on 0-n, returns first element in the list or default() if 0 
list.FirstOrDefault();
//success 1-n, returns the first element in the list
list.First();

//success on 0-n, returns first element in the list or default() if 0 
list.LastOrDefault();
//success 1-n, returns the last element in the list
list.Last();

สำหรับนิพจน์ Linq เพิ่มเติมโปรดดูที่System.Linq.Expressions

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