2016-01-21 17 views
6

olan bir sarmalayıcı nesnesi oluştururken Include sorgumda gezinme özelliğini ekliyorum, böylece daha sonra yüklenmeyecek. Ancak, Select projeksiyon ile anonim bir sarmalayıcı nesne oluşturduğumda işe yaramıyor.EF: "İçine Ekle" gezinme özelliği, "Seçim" projeksiyonu

Basitleştirilmiş örneği göstereyim. varlık:

public class UserEntity { 
    public string Name {get;set;} 
    public virtual ICollection<UserEntity> Friends { get; set; } 
} 

sorgu: Ben oluşturulan SQL ayrıca bkz

var entry = _dbCtx 
    .Users 
    .Include(x => x.Friends) 
    // Select here is simplified, but it shows the wrapping 
    .Select(user => new { 
     User = user 
    }) 
    .First(); 

// Here we have additional lazy loaded DB call 
var friends = entry.User.Friends.Select(x => x.Name).ToList(); 

Ve bu navigasyon özelliği dahil değildir:

SELECT 
    [Limit1].[Name] AS [Name], 
    FROM (SELECT TOP (1) 
     [Extent1].[Name] AS [Name] 
     FROM [dbo].[Users] AS [Extent1] 
    ) AS [Limit1] 

mümkün mü Include'a göre navigasyon özelliği Friends Bu durumda, User, tembel yükleme olmadan veri alacak?

var entry = _dbCtx 
    .Users 
    .Select(user => new { 
     User = user 
    }) 
    .Include(x => x.User.Friends) 
    .First(); 

Ama bir özel durum alma:

Ben bu işe de bekliyordum

InvalidOperationException: Sorgunun sonuç tipi bir EntityType ne de bir varlık unsuru türüyle bir CollectionType ne olduğunu . İçerme yolu, yalnızca bu sonuç türlerinden birine sahip bir sorgu için belirtilebilir.

Orada geldi bazı geçici çözümler vardır, ancak bunlar her nasılsa zor şunlardır:

  1. Select bizim anonim nesneye ekleme özelliğini ekleyin:

    var entry = _dbCtx 
        .Users 
        .Select(user => new { 
         User = user, 
         UsersFriends = user.Friends 
        }) 
        .First(); 
    
    // manually copy the navigation property 
    entry.User.Friends = user.UsersFriends; 
    
    // Now we don't have any addition queries 
    var friends = entry.User.Friends.Select(x => x.Name).ToList(); 
    
  2. Harita ayrıca Kullanıcı DB düzeyinde anonim nesne ve C# UserEntity özelliklerini eşlemek.

    var entry = _dbCtx 
        .Users 
        .Select(user => new { 
         User = new { 
          Name = user.Name, 
          Friends = user.Friends 
         } 
        }) 
        .Take(1) 
        // Fetch the DB 
        .ToList() 
        .Select(x => new { 
         User = new UserEntity { 
          Name = x.Name, 
          Friends = x.Friends 
         } 
        }) 
        .First(); 
    
    // Now we don't have any addition queries 
    var friends = entry.User.Friends.Select(x => x.Name).ToList(); 
    

Yani şimdi, Friends için LEFT OUTER JOIN yoktur, ancak her iki geçici çözümler oldukça iyi değildir:

1) Ek özellikler ve bir kopyası temiz bir yol değildir.

2) UserEntity ürünümün başka özellikleri var. Ayrıca, her yeni mülk eklediğimizde, buradaki seçicileri de değiştirmeliyiz.

İlk örnekten de dahil olmak üzere gezinme özelliğini elde etmenin bir yolu var mı?

Okuduğunuz için teşekkür ederim ve umarım birinin bunun için bir ipucu vardır.

DÜZENLEME:

Ben gerçek kullanım senaryosunu göstermek için varlık ve sorguyu uzatacaktır.

Varlık

public class UserEntity { 
    public string Name {get;set;} 
    public int Score {get;set;} 
    public virtual ICollection<UserEntity> Friends { get; set; } 
} 

Sorgu _why_ olarak

var entry = _dbCtx 
    .Users 
    .Include(x => x.Friends) 
    .Select(user => new { 
     User = user, 
     Position = _dbCtx.Users.Count(y => y.Score > user.Score) 
    }) 
    .First(); 

cevap

0

Sorumun cevabı değil ama

Aslında değilim ... iyi kod biçimlendirme istedi Şaşırır böyle çalışır. Belki de EF, Friends özelliğini doğrudan projeksiyonunuzda kullanmadığınızı ve dolayısıyla görmezden geldiğinizi saptamaktadır.

var entry = _dbCtx 
    .Users 
    .Include(x => x.Friends) 
    .Take(1); // replicate "First" inside the EF query to reduce traffic 
    .AsEnumerable() // shift to linq-to-objects 
    // Select here is simplified, but it shows the wrapping 
    .Select(user => new { 
     User = user 
    }) 
    .First() 
+0

biz (sorgusunun ardından) 'C#' tarafında bir sarıcı nesne oluşturmak Olarak örnek çalışacak, değil sql' 'ile: Eğer EF sorgusunun dışında nesne (ler) kapsüllü ne. Ama buna db düzeyinde ihtiyacım vardı. Nedeni: "Seç" ile ek alt sorgu gerçekleştiriyorum. İlginç bir şey, benim ilk geçici çözümümüzü görmemize rağmen, 'user.Friends' sorgusunda kullanıyoruz, ancak materyalizasyondan sonra Mülkiyet'i tekrar objeye kopyalamamız gerekiyor, aksi takdirde yine de tembel bir yükleme olacaktı. – tenbits

+0

Neden db sorgusunda anonim bir türe yansıtmanız gerekiyor? Anladığım kadarıyla aynı sonucu elde edersin. Yoksa, SQL'e yansıtmak istediğiniz _additional_ yöntemlerini ('Where',' OrderBy', vb.) Mi yansıtıyorsunuz? –

+0

Gönderi düzenlemelerime bakın, bir kullanıcı için alt sorgu yapıyorum ve her kullanıcı üzerinde yinelediği için DB'de yapılmalıdır. Performans nedeniyle, bunu C# ile yapamıyorum. – tenbits