Kodda xatolarni tuzatishning eng yaxshi yo'li qanday?

Xatolikni tekshirib ko'rishimga biroz tashvishlanyapman ... Hozirda mening bajarishim shunday ko'rinadi:

Users.aspx -> App_Code/User.cs -> Data Layer/User.cs

Shuning uchun endi foydalanuvchi yozuvini yangilashga harakat qilsam, harakatni ishlov berish apparatida "Try/Catch" blokini qo'yaman va faqat App_Code ma'ruza ma'lumot qatlami bilan o'zaro bog'lanishiga ishonch hosil qilaman. Ma'lumotlar sathida yuzaga keladigan istisnolar, mening tushunchamga muvofiq, quyidagi voqea ishlov beruvchisiga aylanishi kerak.

Ma'lumotlar sathida men bu bilan boshladim:

public void Update()
{
    var product = (from p in db.products
                        where p.productid == id
                        select p).FirstOrDefault();

    if (product != null)
    {
       //update the thing
    }
}

Qo'shimcha ma'lumot Reddit .

Do'stingiz bilan suhbatlashgandan keyin u shunday maslahat berdi:

public void Update()
{
    int count = db.users.Count(u => u.userid == id);

    if (count == 0)//no user found
    {
        throw new ValidationException(String.Format("User not found for id {0}.", id));
    }
    if (count > 1)//multiple users
    {
        throw new ValidationException(String.Format("Multiple users found for id {0}.", id));
    }

    var user = db.users.FirstOrDefault(u => u.userid == id);
   //update the user record
}

Keyin IRCga bordim, ular O'z istisnootlarni yaratish ni taklif qildilar.

Men bu erda yaxshi tomonlarini ko'rishim mumkin, lekin do'stimning imkoniyati yaxshi ishlayotganida, bu biroz keraksiz ko'rinadi.

Asosan, men buni qanday qilish kerakligi haqida shunchaki chalkashibman ... Shubhasiz, mening dastlabki variantim etarli emas, lekin o'z istisnolarimni yaratish kabi narsalar juda ko'p narsani murakkablashtirishi mumkin.

Xo'sh, men bu erda nima qilishim kerak?

3
Ikkala misol xuddi shu narsani qilmaydi. Birinchi misol, foydalanuvchi mavjud bo'lmagan yoki bir nechta foydalanuvchi topilgan vaziyatlarni e'tiborsiz qoldiradi. Ikkinchi misol, qo'ng'iroq qiluvchining ushbu vaziyatlarni bartaraf etishga majbur qiladi yoki dastur davom etmaydi.
qo'shib qo'ydi muallif Maleev, manba
@JimmyHoffa "Eng yaxshi usuli" bo'lishi mumkin emas, lekin barcha alternativlardan pastroq bo'lgan usullar kam. Bunday holatda, null ni qaytarish.
qo'shib qo'ydi muallif Doval, manba
Men dasturiy muhandislik va dizayndagi biror narsa qilishni xohlayman, buni amalga oshirish uchun eng yaxshi usuli bor ... Men bu borada ishlashga harakat qilaman, chunki men doimo aniq dasturiy ta'minotni ishlab chiqish bilan shug'ullanmayman, chunki men doimo nomukammal echimlar
qo'shib qo'ydi muallif Jimmy Hoffa, manba
@Doval ah bu null monadda emassan, agar yomon bo'lsa ...
qo'shib qo'ydi muallif Jimmy Hoffa, manba
Siz asosan siz yuborgan ikkinchi parcha o'rtasida qaror qabul qilmoqchisiz va o'zingiz foydalangan Exception pastki sinflarni yaratishingiz mumkinmi? Men ikkalasining orasidagi farqni ehtimol kichik deb hisoblayman, bu juda ham oson ish emas
qo'shib qo'ydi muallif Ben Aaronson, manba
Juda yaxshi aytdim, Jimmy Hoffa
qo'shib qo'ydi muallif sharanaprasad mailar, manba
@BenAaronson ma'qulladi, lekin so'rovdan qaytib kelgan yozuvlar sonini olish va undan keyin qaytarilgan ma'lumotni olish natijasi samarasiz ekanligi menga o'xshaydi. Men asosan eng yaxshi amaliyot haqida g'oyani olishga harakat qilyapman
qo'shib qo'ydi muallif sharanaprasad mailar, manba

6 javoblar

Maxsus istisnolardan foydalanishning sababi siz ular bilan foydali bo'lgan biror narsa qilish niyatidadir.

Foydalanuvchini "foydali" deb ko'rsatyaptimi?
Ehtimol, yo'q. Ular qo'rqinchli ko'rinadi.

Keyinchalik "foydali" muoyana uchun ularni faylga yozib qo'yadimi? Ehtimol, ayniqsa, agar dastur "global" istisno ishlovchilarida (ular uchun yaxshi bo'lgan all ) bo'lsa, buni amalga oshirish va o'lishga to'g'ri keladi.

tutuvchi muayyan bir istisno turi va uni boshqarish (masalan, muammo bilan shug'ullanish uchun yozish kodi va to'g'ri bu muammoni hal qilish uchun, tercihen foydalanuvchi har qanday narsa haqida ) "foydali"? Oh Ha!

Nima uchun maxsus istisno turlari dan foydalaniladi? Chunki ko'pchilik tillar aniqlash istisnosini kutadi. "Tut" iboralarini ko'rib chiqing - ular muayyan istisno turlarini izlashadi. Buni aytish uchun uzr so'rayman, lekin do'stingizning tavsiyasi bilan qat'iyan rozi bo'laman - xuddi shu [sinf] ValidationException [ob'ektlar] ni bir joyga tashlab, nima sodir bo'layotganini tushuntirish uchun Matn xususiyatiga suyanaman. Bu faqat bitta stsenariyda foydalidir - istisnolardan foydalanuvchi uchun to'g'ridan-to'g'ri ko'rsatadigan va bu mening kitobimda juda yomon amaliyotdir.

3
qo'shib qo'ydi
@mau Bu mening kelishmovchilik bilan kelishuvga o'xshashdir
qo'shib qo'ydi muallif Ben Aaronson, manba
Men bunga qo'shilmayman, ishlab chiqarish kodidagi istisnolardan foydalanishni disk raskadrovka uchun juda foydali bo'lishi mumkin. Xo'sh, bunga baribir rozi bo'lmaysiz - buni eslatib o'tmoqchisiz, faqatgina "ehtimol" foydali deb aytsangiz, u holda sizning xulosangizga e'tiborsiz bo'lib tuyuladi.
qo'shib qo'ydi muallif Ben Aaronson, manba
@BenAaronson Men sizning kelishmovchiliklaringiz bilan rozi emasman: D ishlab chiqarishni ochish, aslida to'g'ri bajarilgan taqdirda juda foydali. Ishlashni zaiflashtirmasa, bu xatolarni takrorlash va hatto javob berish vaqti, auditoriya kabi boshqa narsalarni o'lchashda katta qadamdir.
qo'shib qo'ydi muallif mau, manba
Shunday qilib, men xatolikni tuzatmoqchi bo'lganimda va tuzumni menga tuzatish uchun elektron pochta tizimiga ega bo'lishni istasam, bu "foydali" bo'lar edi?
qo'shib qo'ydi muallif sharanaprasad mailar, manba
Bundan tashqari, hozirgi paytda kod hozircha turibdi, men bu muammoni foydalanuvchi bilan bog'lashni istayman ...
qo'shib qo'ydi muallif sharanaprasad mailar, manba

Ushbu maxsus vaziyatda LINQ ning Single usulidan foydalanish yaxshiroq bo'lishi mumkin:

public void Update()
{
    var user = db.users.Single(u => u.userid == id);
   //update the user record
}

Single already does exactly what you want: it throws an Exception if there are 0 or more than 1 results matching the predicate.

Ushbu nuqtada siz Single kodirovkasi orqali sizning istaganingizdan baxtiyormisiz yoki uni foydali ma'lumot bilan yoki muayyan turdagi birlashtirmoqchi bo'lganingizdan xursand bo'lishingiz mumkin. Buning umumiy shakli quyidagicha bo'ladi:

public void Update()
{
    try
    {
        var user = db.users.Single(u => u.userid == id);
    }
    catch(SomeExceptionType ex)
    {
        throw new SomeOtherExceptionType("Useful message here", ex);
    }
   //update the user record
}

Bu erda someOtherExceptionType asoschisiga ex o'tishni bildiradi, bu asl istisnosiz saqlanishi kerak bo'lgan ma'lumotni odatda yaxshi umumiy amaliyot sifatida beradi)

Izohda aytib o'tganimdek, buning qanday aniqligini tanlash, ehtimol, o'ta muhim emas. Mening maslahatim oddiy variant bilan boshlanishi kerak edi - bu holda o'z istisnosizni va kerak bo'lganda uni qayta tiklash uchun Single ni berishga imkon berdi.

Agar siz aniqroq maxsus holat xabarini ko'rsatish yoki uni saqlash kerak bo'lsa, o'zingizni topsangiz, bu usulda istalgan vaziyatni saqlang yoki chaqiriq zanjirini kerakli darajada balandlang. Buni qaerda qilsangiz, sizning abstraktsiya darajangiz o'rtasida sızmaktan kaçınmalısınız. Quyidagilarga e'tibor bering:

public void HighLevelMethod()
{
    try
    {
        DataAccessClass.Update();
    }
    catch(Exception ex)
    {
        throw new SomeKindOfException("What should I say here?", ex);
    }
}

Bu erda xabar HighLevelMethod uchun munosib soyutlama darajasida bo'lishi kerak. "Yangilash muvaffaqiyatsiz tugadi" degan satrda bir narsa (garchi ideal biroz foydali bo'lsa ham!). Yangilanishni amalga oshirishning aniq sababi Update ichida saqlanadi, shuning uchun xabardan "yangilash hech qanday foydalanuvchi topilmagani uchun muvaffaqiyatsiz" bo'lishi uchun ajralish qatlamlari orasida dastur tafsilotlariga sabab bo'lishi mumkin. Agar batafsil ma'lumotni ko'rsatishni xohlasangiz, u holda bu xabar Update tomonidan tuzilgan istisno holatiga o'tishi kerak.

Xuddi shu tarzda o'zingizning Istisno pastki klassini tashlash uchun faqat refactor siz o'zingizning o'zingizning qo'ng'iroqlar zanjirini yuqoriga ko'tarish kerakligini biladigan ba'zi bir foydali ma'lumotni beradi. Update() kodini chaqiradigan kod ValidationException ga nisbatan UserNotFoundException bilan ishlashning boshqa usuliga ega? Aks holda, Exception o'zingiz bilan bezovta qilmang.

Agar siz boshqa, tashqi, kod tomonidan ishlatiladigan kutubxonani yozmoqchi bo'lsangiz, maxsus xabarlar yoki maxsus Exception turlaridan foydalanganda ishlab chiqishda biroz ko'proq pro-faol bo'lishingiz kerak, ehtiyoj bor ekan, kutish o'rniga emas. Lekin ayni umumiy tamoyillar qo'llaniladi.

3
qo'shib qo'ydi

Dl;

Men aytmoqchimanki, ular siz uchun istisno emas, chunki siz ularni yangilashdan oldin ularni tekshirib ko'rishingiz kerak. Yangilanish nuqtasiga kirgan vaqtingizda tarmoqdagi xato, db himoyasi yoki db mavjud emas. harakatlaringiz nazoratdan tashqarida. Agar siz o'zingiz nazorat qilayotgan narsalarni tekshirib qo'ysangiz, sizning arizangiz oqim sizni nazorat qiladi va istisnolar asosida emas. Istisnolar qimmatga tushadi, shuning uchun dastur oqimini nazorat qilish uchun ularni ishlatmaslik kerak.

0
qo'shib qo'ydi
Nimaga yangilanishni chaqirishdan oldin kodni kodni bir xil joyda bir vaqtning o'zida tekshiruvda tekshirib bo'lmaydi. Yangilanishni faqatgina istisnolar ataladi. Men sizning fikringizni ko'rishingiz mumkin, ammo bu uslubning uslubi.
qo'shib qo'ydi muallif Rick, manba
Ushbu kontekstda o'zaro muvozanat tekshiruvi orqali nimani nazarda tutayotganingizga amin emasman. Lekin Update bir nechta joydan chaqirilishi mumkinligini taxmin qilsangiz, uni tekshirishdan oldin tekshirishni amalga oshirish kerak bo'lsa, o'zingizni takrorlash kerak degan ma'noni anglatadi.
qo'shib qo'ydi muallif Ben Aaronson, manba
Ilovalar oqimini nazorat qilish uchun istisnolar bu erda qo'llanilgan deb o'ylamayman. Ular asosan old shartlar sifatida ishlatiladi. Buning hech qanday yomon joyi yo'q. Bu kabi sezgir tekshiruvlar kutilmagan vaziyatlar yuzaga kelganda, tizim orqali tarqaladigan va g'alati xatti-harakatlar va/yoki istisnolarning bir joyga noqonuniy ravishda disk raskadrovka qilishiga olib keladigan muammolar o'rniga foydali joylardan tashqariga chiqishiga imkon beradi. Agar siz hech qanday aql bovar qilmaydigan boshlang'ich nuqtasi bo'lmagan DAL bilan o'zaro ta'sir qiladigan hech qanday kodda xato bo'lmasa, siz bahslashmoqdasiz.
qo'shib qo'ydi muallif Ben Aaronson, manba

Men Entity Framework dasturidan foydalanmayman, lekin menimcha, xuddi shu qoidalar amal qiladi. Odatda nima qilsam lambda ichidagi barcha ma'lumotlar bazalarini chaqiradi va har bir operatsiya uchun ushbu kod blokini qayta ishlatadi. Lambda tashqarisida sinash/tutish bloklarini ishlataman, shuning uchun har qanday istisno xuddi shu yo'lga yo'naltiriladi, shuning uchun har bir xatoni o'zlariga ochiq qilish kerak emas. Agar natija istisno qilsa, men boshqacha qilib qo'yaman.

Agar mijozga ma'lumot jo'natishim kerak bo'lgan maxsus xabar bo'lsa, odatda lambda kodidan ichki istisnoga tashlayman, shuning uchun lambda tashqarisida pufakchaga tushadi va mijozga texnik bo'lmagan xabar keladi.

Menimcha, barcha istisnolar bir tarzda saqlanib qolishi kerak, yana uni yuqori darajadagi, lambda tashqarisida ogohlantirish sifatida bajarish (masalan, xatoliklar uchun xatoliklar kerak emas, lekin nuqsonli qiymat).

Siz ko'rsatayotgan Qo'shimchalar/Yangilash mantiqiga kelsak, siz yaratish uchun bir usul va yangilash uchun boshqa usuldan foydalanishingiz mumkin. Agar shunday bo'lsa, id yangilash usulida topilmasa, siz istisno qilasiz. Ammo, odatda, agar siz id ma'lumotlar bazasida topilmasa, menimcha, bu ikkita usuliga ega bo'lishdan ko'ra, "upsert" so'rayman.

Maybe looking into this example it will be clear what I mean: Database Wrapper

0
qo'shib qo'ydi
Ha, yaxshi. Bu qanday foydali bo'lishi mumkinligini ko'rib turibman, garchi u me'morchilikka bog'liq bo'lsa ham. Misol uchun, agar EF ning ustki qismida repository naqshlaridan foydalanilsa, bu kabi istisno "marshrut" kodini qo'yish uchun ko'proq tabiiy joy bo'lishi mumkin.
qo'shib qo'ydi muallif Ben Aaronson, manba
analizeException orqasida yashirgan narsalaringizning ko'pi bilan bog'liq bo'lgan Ortund nima degan savolga shubha qilaman.
qo'shib qo'ydi muallif Ben Aaronson, manba
Albatta, bu mavhum qaror, ehtimol boshqa arquitecture bilan ishlamaydi. Faqat bir qancha loyihalar uchun foydalanadigan fikrni ko'rsatmoqchi edim. Men EFni uzoq vaqtdan beri ishlatmadim, ServiceStack OrmLite xizmatidan foydalanmoqchi edim.
qo'shib qo'ydi muallif mau, manba
@BenAaronson aslida analizeException ma'lumotlar bazasi xabarlarini tekshirish va inson tomonidan o'qiladigan matnni tarjima qilish uchun faqat regex baholash hisoblanadi. Barcha go'sht men ko'rsatgan kod bo'yicha.
qo'shib qo'ydi muallif mau, manba

Asosan bu sizning qo'zg'olon bayonotlarini qanday qilib boshqarishni xohlasa bog'liq. O'zingizning maxsus istisnolaringiz bo'lishining afzalligi ularni alohida-alohida qo'lga olishingiz va alohida kod qismlarini bajarishingiz mumkin, quyida ko'rib chiqing. Biroq, istisnolaringizning barcha turlarini faqat rejalashtirishni rejalashtirayotgan bo'lsangiz, xuddi shu kabi xabarni log faylga yoki xabar qutisiga tushirish kabi umumiy istisnolardan foydalansangiz yaxshi bo'ladi.

catch (UserNotFoundException ex) 
{ 
    //handle code for user's not found
}
catch (MultipleUsersFoundException ex) 
{
    //handle code for multiple users
}
catch (Exception ex) 
{ 
    //handle other badness
}
0
qo'shib qo'ydi

Siz uchun eng mantiqiy nima? ValidationException muammoni aniq tasvirlab beradimi? Agar shunday bo'lsa, uni ishlatib, yaxshi va to'g'ri xabarni yuborish bilan hech qanday xato yo'q. Agar siz aniqroq xato xabari qilishni xohlasangiz, ValidationException, ya'ni "UserNotFoundException" va "ManyUsersFoundException" ni egallaydigan istisno sinf yaratishingiz mumkin. Bu, ehtimol, kambag'al nomlar va siz istagan narsalar emas, balki siz fikrni olasiz.

Shuningdek...

var user = db.users.FirstOrDefault(u => u.userid == id);

Sizning kodingiz "FirstOrDefault" dan foydalanish uchun biroz ko'proq kerak. Siz allaqachon bilasizlarki, shu nuqtada sizda biror rekord bor. Shunday qilib, siz ishonch bilan foydalanishingiz mumkin:

var user = db.users.First(u => u.userid == id);

Va u bilan hech qanday oqibatlarga olib keling.

Bundan tashqari, men sizning do'stingiz bilan suhbatga asoslangan modifikatsiyalaringiz menga etarli darajada ko'proq ko'rinadi, deb aytaman. Lekin bu shaxsiy fikr.

0
qo'shib qo'ydi