Yanıtlar:
Başkalarının neden birini veya diğerini kullandığınızı yazdığını biliyorum, ama neden birini kullanmamanız gerektiğini açıklayacağımı düşündüm. diğerini kastettiğinizde .
Not: Kodumda genellikle kullanacağım FirstOrDefault()
ve SingleOrDefault()
bu farklı bir soru.
Örneğin, Customers
Kompozit Anahtar ( ID
, Lang
) kullanarak farklı dillerde depolanan bir tabloyu ele alalım :
DBContext db = new DBContext();
Customer customer = db.Customers.Where( c=> c.ID == 5 ).First();
Yukarıdaki bu kod olası bir mantık hatası verir (izlenmesi zor). Birden fazla kayıt döndürür (birden fazla dilde müşteri kaydına sahip olduğunuzu varsayarsak), ancak her zaman yalnızca ilk kaydı döndürür ... bazen işe yarayabilir ... ancak diğerleri değil. Tahmin edilemez.
Amacınız tek Customer
kullanımlık geri dönüş yapmak olduğundanSingle()
;
Aşağıdakiler bir istisna atar (bu durumda istediğiniz şeydir):
DBContext db = new DBContext();
Customer customer = db.Customers.Where( c=> c.ID == 5 ).Single();
O zaman, sadece alnına vur ve kendine söyle ... OOPS! Dil alanını unuttum! Doğru sürüm aşağıdadır:
DBContext db = new DBContext();
Customer customer = db.Customers.Where( c=> c.ID == 5 && c.Lang == "en" ).Single();
First()
aşağıdaki senaryoda yararlıdır:
DBContext db = new DBContext();
NewsItem newsitem = db.NewsItems.OrderByDescending( n => n.AddedDate ).First();
ONE nesnesini döndürür ve sıralamayı kullandığınız için, döndürülen en son kayıt olur.
Single()
Her zaman 1 kayıt döndürmesi gerektiğini düşündüğünüzde kullanmak , mantık hatalarından kaçınmanıza yardımcı olacaktır.
customers.Where(predicate).Single()
customers.Single(predicate)
mı?
Single, ölçütlerle eşleşen birden fazla kayıt bulursa bir istisna atar. İlk önce her zaman listeden ilk kaydı seçer. Sorgu yalnızca 1 kayıt döndürürse, ile devam edebilirsiniz First()
.
InvalidOperationException
Koleksiyon boşsa her ikisi de bir istisna atar . Alternatif olarak kullanabilirsiniz SingleOrDefault()
. Liste boşsa bu bir istisna oluşturmaz
Tek()
Bir sorgunun tek bir belirli öğesini döndürür
Kullanıldığında : Tam olarak 1 eleman bekleniyorsa; 0 veya 1'den fazla değil. Liste boşsa veya birden fazla öğeye sahipse, "Sıra birden fazla öğe içerir"
SingleOrDefault ()
Bir sorgunun tek bir belirli öğesini veya sonuç bulunamazsa varsayılan bir değer döndürür
Ne Zaman Kullanılır : 0 veya 1 eleman beklendiğinde. Listede 2 veya daha fazla öğe varsa bir istisna atar.
İlk()
Birden çok sonuç içeren bir sorgunun ilk öğesini döndürür.
Ne zaman Kullanılır : 1 veya daha fazla eleman beklendiğinde ve yalnızca ilk eleman istediğinizde. Listede öğe yoksa istisna atar.
FirstOrDefault ()
Herhangi bir miktarda öğeye sahip bir listenin ilk öğesini veya liste boşsa varsayılan değeri döndürür.
Ne zaman Kullanılır : Birden fazla eleman beklendiğinde ve yalnızca ilkini istediğinizde. Veya liste boştur ve belirtilen tür için varsayılan değerle aynıdır
default(MyObjectType)
. Örneğin: liste türü ise, listedenlist<int>
ilk sayıyı veya liste boşsa 0 değerini döndürür. Öyleyselist<string>
, listeden ilk dizeyi veya liste boşsa null değerini döndürür.
First
zaman 1 veya daha fazla öğe bekleniyor "1'den fazla" ve sadece, FirstOrDefault
elemanların herhangi bir miktar ile.
Bu iki yöntem arasında ince, anlamsal bir fark vardır.
Single
İlk (ve yalnızca) öğeyi, bir öğe içermesi ve daha fazla içermemesi gereken bir diziden almak için kullanın . Dizide birden fazla öğe Single
varsa, yalnızca tek bir öğe olması gerektiğini belirttiğiniz için çağrmanız bir istisna oluşmasına neden olur.
First
Herhangi bir sayıda öğe içerebilen bir diziden ilk öğeyi almak için kullanın . Dizide birden fazla öğe varsa, dizideki First
ilk öğeye ihtiyacınız olduğunu ve daha fazla var olup olmadığını umursamadığınızı belirttiğiniz için çağrmanızın bir istisna oluşmasına neden olmaz.
Dizi hiçbir öğe içermiyorsa, her iki yöntem de en az bir öğenin bulunmasını beklediğinden, her iki yöntem çağrısı da istisnaların atılmasına neden olur.
Birden fazla öğe olması durumunda özellikle bir istisna oluşturulmasını istemiyorsanız, kullanınFirst()
.
Her ikisi de verimli, ilk öğeyi al. First()
biraz daha etkilidir çünkü ikinci bir öğe olup olmadığını kontrol etmeyi zahmet etmemektedir.
Tek fark, Single()
numaralandırmada başlamak için sadece bir öğe olmasını ve birden fazla varsa bir istisna atmasıdır. Sen kullanmak .Single()
özel olarak atılmış bir istisna istiyorsanız bu durumda.
Hatırlıyorsam, Single () ilkinden sonra başka bir öğe olup olmadığını kontrol eder (ve bu durumda bir istisna atar), First () ise aldıktan sonra durur. Dizi boşsa her ikisi de bir istisna atar.
Şahsen ben her zaman First () kullanıyorum.
Performans konusunda: Bir iş arkadaşım ve ben Single - First (ya da SingleOrDefault vs FirstOrDefault) performansını tartışıyorduk ve First (ya da FirstOrDefault) 'un daha hızlı olacağı ve performansı geliştireceğimi tartışıyordum daha hızlı koş).
Stack Overflow'da bu konuyu tartışan birkaç yazı okudum. Bazıları, Single yerine First kullanarak küçük performans kazanımları olduğunu söylüyor. Bunun nedeni, First'in yalnızca ilk öğeyi döndürmesi ve Single'ın tüm sonuçları taraması gerektiğinden emin olmaktır (yani: öğeyi tablonun ilk satırında bulmuşsa, diğer tüm satırları koşulla eşleşen ve ardından bir hata atacak ikinci bir değer olmadığından emin olun). Sağlam bir zeminde olduğumu hissettim, “İlk” in “Bekar” dan daha hızlı olması bu yüzden bunu kanıtlamaya ve tartışmayı dinlendirmeye başladım.
Veritabanımda bir test oluşturdum ve 1.000.000 satır ID UniqueIdentifier Foreign UniqueIdentifier Info nvarchar (50) (“999,9999” a “0” sayı dizeleriyle dolu) ekledim
Verileri yükledim ve kimliği birincil anahtar alanı olarak ayarladım.
LinqPad kullanarak amacım, Single ile 'Yabancı' veya 'Bilgi' üzerinde bir değer aradığınızda, İlk'i kullanmaktan çok daha kötü olacağını göstermekti.
Elde ettiğim sonuçları açıklayamıyorum. Hemen hemen her durumda, Single veya SingleOrDefault kullanmak biraz daha hızlıydı. Bu benim için mantıklı değil, ama bunu paylaşmak istedim.
Örnek: Aşağıdaki sorguları kullandım:
var q = TestTables.First(x=>x.Info == "314638") ;
//Vs.
Var q = TestTables.Single(x=>x.Info =="314638") ; //(this was slightly faster to my surprise)
Ben 'Yabancı' anahtar alanında benzer sorguları denedim ki bu, İlk'in daha hızlı olduğunu, ancak Single'ın testlerimde her zaman biraz daha hızlı olduğunu düşünerek endekslenmedi.
Onlar farklı. Her ikisi de sonuç kümesinin boş olmadığını iddia ediyor, ancak single da 1'den fazla sonuç olmadığını iddia ediyor. Ben sadece 1 sonuç daha geri almak bir hata olduğundan ve muhtemelen böyle tedavi edilmelidir çünkü ben sadece 1 sonuç olmasını beklediğiniz durumlarda şahsen Tek kullanın.
Fark almak için basit bir örnek deneyebilirsiniz. 3. satırda istisna atılacaktır;
List<int> records = new List<int>{1,1,3,4,5,6};
var record = records.First(x => x == 1);
record = records.Single(x => x == 1);
Çalışan varlığındaki kayıtlar:
Employeeid = 1
: Bu kimliğe sahip yalnızca bir çalışan
Firstname = Robert
: Bu ada sahip birden fazla çalışan
Employeeid = 10
: Bu kimliğe sahip çalışan yok
Şimdi ne olduğunu Single()
ve ne First()
anlama geldiğini ayrıntılı olarak anlamak gerekiyor .
Tek()
Sorgu aşağıda kimin Çalışan dönecektir böylece Single (), benzersiz bir tablo var tek bir kayıt döndürmek için kullanılır employeed =1
kimin tek Çalışan var çünkü Employeed
biz iki kayıtlarınız varsa 1'dir EmployeeId = 1
o zaman bir hata atar (bkz için bir örnek kullandığımız ikinci sorguda aşağıdaki hata Firstname
.
Employee.Single(e => e.Employeeid == 1)
Yukarıdaki tek bir kayıt dönecektir, hangi 1 employeeId
Employee.Single(e => e.Firstname == "Robert")
Yukarıdakiler bir istisna atar çünkü çoklu kayıtlar tablodadır FirstName='Robert'
. İstisna
InvalidOperationException: Sıra birden fazla öğe içeriyor
Employee.Single(e => e.Employeeid == 10)
İd = 10 için kayıt olmadığı için bu yine bir istisna atar. İstisna olacak
InvalidOperationException: Sekans öğe içermiyor.
Çünkü EmployeeId = 10
null döndürür, ancak kullandığımız Single()
için bir hata atar. Boş hatayı işlemek için kullanmalıyız SingleOrDefault()
.
İlk()
İlk olarak () birden fazla kayıttan artan sıraya göre sıralanan kayıtlar birthdate
döndürülür , böylece en eski olan 'Robert' döndürülür.
Employee.OrderBy(e => e. Birthdate)
.First(e => e.Firstname == "Robert")
Yukarıdaki DOB göre en eski olanı, Robert dönmelidir.
Employee.OrderBy(e => e. Birthdate)
.First(e => e.Employeeid == 10)
Yukarıdaki id = 10 kaydı olmadığından istisna atar. Boş bir istisnayı önlemek için kullanmak FirstOrDefault()
yerine kullanmalıyız First()
.
Not: Yalnızca First()
/ Single()
boş bir değer döndüremeyeceğinden emin olduğumuzda / kullanabiliriz .
Her iki işlevde de tek bir istisna işleyecek olan SingleOrDefault () VEYA FirstOrDefault () kullanın , hiçbir kayıt bulunamaması durumunda null değerini döndürür.