2013-06-13 17 views
8

Bir sayfada önceden yüklenen ürünlerin listesinden farklı renklerin bir listesini yüklemeye çalışıyorum. Bu yüzden bunu ürünlerde çekme:Varlık Çerçevesi AsNoTracking molaları Ayrı olarak adlandırılıyor

Sonra
var products = Products 
    .Include(p => p.ProductColor) 
    .ToList(); 

ben ürünleri tarafından kullanılan farklı renklerin bir listesini almak istiyorum bunlardan ürünlerde bazı işlem yapmak, bu yüzden bunu:

var colors = products 
    .Select(p => p.ProductColor) 
    .Distinct(); 

Ve bu harika çalışıyor, ancak orijinal ürün çağrısına .AsNoTracking() numaralı telefona bir çağrı eklerseniz, şimdi ürün listemdeki her giriş için renk listemde bir giriş elde ediyorum.

Bu ikisinde neden bir fark var? Entity Framework'ün nesneleri takip etmesini (yalnızca okumak için kullanılıyor) ve istenen davranışı elde etmesinin bir yolu var mı?

İşte AsNoTracking()

var products = Products 
    .AsNoTracking() 
    .Include(p => p.ProductColor) 
    .ToList(); 
+0

Yayınladığınız sayfadan .AsNoTracking sorgusuma girdiğinizde tam olarak yazmalı, –

+0

@LukeMcGregor, '.AsNoTracking' ile yaptığım sorguyu kullanarak bu sorunu güncelledim – heavyd

+0

Sadece bir yazım hatası mı yazdı sorgu ToList ile biter ve içinde hiç bir farklılık yok mu? –

cevap

19

AsNoTracking "sonları" DistinctAsNoTracking çünkü "tatili" kimlik haritalama çağrısı ekledikten sonra benim sorgusu olur. AsNoTracking() ile yüklenen varlıklar, bağlam önbelleğine eklenmeyeceğinden, ASP, sorgudan döndürülen her satır için yeni öğeler oluşturur, oysa izleme etkinleştirildiğinde, aynı anahtar değerine sahip bir varlığın zaten var olup olmadığını ve eğer evet ise Yeni bir nesne oluşturmaz ve bunun yerine yalnızca ekli nesne örneğini kullanır. Eğer 2 ürün varsa ve

Örneğin, her iki Yeşil şunlardır: 2 Product nesneleri ve 1 ProductColor nesne (Yeşil): AsNoTracking() Sorgunuzun olmadan

  • 3 nesneleri gerçekleştirmek olacaktır. Ürün 1 (ProductColor özelliğinde) yeşil bir referans yer alır ve ürün 2 sorgu 4 nesneleri somutlaşacaktır yani AsNoTracking() ile

    object.ReferenceEquals(product1.ProductColor, product2.ProductColor) == true 
    
  • aynı eleman örneği yeşil bir başvuru var 2 ürün nesneleri ve 2 renkli nesneler (her ikisi de Yeşil'i temsil eder ve aynı anahtar değere sahiptir). Ürün 1 (ProductColor özelliğinde) Green bir referansı vardır ve Ürün 2 Green'e bir referansı vardır ama bir koleksiyonda üzerinde Distinct() çağırırsanız bu, Şimdi yani

object.ReferenceEquals(product1.ProductColor, product2.ProductColor) == false 
başka nesne örneği
olduğunu bellek (LINQ-to-Objects) parametresi olmadan Distinct() için varsayılan karşılaştırma nesne referans kimliklerini karşılaştırıyor. Yani, 1 durumunda sadece 1 Green nesnesi alırsınız, ancak 2 durumunda 2 Green nesnesi alırsınız.

Sorguyu AsNoTracking() ile çalıştırdıktan sonra istenen sonucu almak için varlık anahtarıyla bir karşılaştırmaya ihtiyacınız vardır. Parametre olarak IEqualityComparer alan Distinct ikinci aşırı yükünü kullanabilirsiniz. Uygulaması için bir örnek here ve iki nesneyi karşılaştırmak için ProductColor anahtar özelliğini kullanırsınız.

Veya - sıkıcı IEqualityComparer uygulanması daha bana daha kolay görünüyor - Bir GroupBy (gruplama anahtarı olarak sahip ProductColor anahtar özellik) kullanılarak Distinct() yeniden yazın:

var colors = products 
    .Select(p => p.ProductColor) 
    .GroupBy(pc => pc.ProductColorId) 
    .Select(g => g.First()); 

First() temelde demektir tüm kopyaları atar ve sadece ilk nesne örneğini anahtar başına tut.