2015-01-03 6 views
5

पर संबंधित इकाइयों को जोड़ने में सक्षम नहीं है मैं टैग सहित पोस्ट की एक सूची प्राप्त करना चाहता हूं।सी # और ईएफ मॉडल

public class BlogPostGetByUrlSlugDto 
{ 
    public int Id { get; set; } 
    public string Title { get; set; } 
    public string Category { get; set; } 
    public string Color { get; set; } 
    public string UrlSlug { get; set; } 
    public string Description { get; set; } 
    public IList<BlogTagGetByPostIdDto> Tags { get; set; } 
} 

public class BlogTagGetByPostIdDto 
{ 
    public string Name { get; set; } 
    public string UrlSlug { get; set; } 
} 

मेरे कोड अब तक::

public BlogPostGetByUrlSlugDto GetByUrlSlug(string urlSlug) 
{ 
    var blogPostQuery = _blogPostRepository.Query; 

    return blogPostQuery 
       .Where(b => b.UrlSlug.Equals(urlSlug)) 
       .ToList() 
       .Select(bp => new BlogPostGetByUrlSlugDto 
       { 
        Id = bp.Id, 
        Title = bp.Title, 
        Category = bp.BlogCategory.Name, 
        Color = bp.BlogCategory.Color, 
        UrlSlug = bp.UrlSlug, 
        Description = bp.Description, 
        Tags = bp.BlogTags.Select(t => new BlogTagGetByPostIdDto 
             { 
              Name = t.Name, 
              UrlSlug = t.UrlSlug 
             }) 
             .ToList() 
       }) 
       .Single(); 
} 

मैं लाइन .Select(bp => new BlogPostGetByUrlSlugDto में Object reference not set to an instance of an object मिल

मैं मॉडल है।

कोई विचार क्यों?

भंडार_blogPostRepository.Query के लिए है:

public interface IRepository<T> where T : class 
{ 
    T FindById(int id, bool asNoTracking = false); 

    T FindSingle(Expression<Func<T, bool>> predicate = null, bool asNoTracking = false, params Expression<Func<T, object>>[] includes); 

    IQueryable<T> Find(Expression<Func<T, bool>> predicate = null, bool asNoTracking = false, params Expression<Func<T, object>>[] includes); 


    /// <summary> 
    /// Add entity to the repository 
    /// </summary> 
    /// <param name="entity">The entity to add</param> 
    void Add(T entity); 

    /// <summary> 
    /// Attach entity to the repository 
    /// </summary> 
    /// <param name="entity">The entity to attach</param> 
    void Attach(T entity); 

    bool Exists(T entity); 

    /// <summary> 
    /// Updates entity within the repository 
    /// </summary> 
    /// <param name="entity">The entity to update</param> 
    void Update(T entity, bool partial = false); 


    /// <summary> 
    /// Mark entity by id to be deleted within the repository 
    /// </summary> 
    /// <param name="entity">The entity to delete</param> 
    void Delete(object id); 


    /// <summary> 
    /// Mark entity to be deleted within the repository 
    /// </summary> 
    /// <param name="entity">The entity to delete</param> 
    void Delete(T entity); 


    /// <summary> 
    /// Get an item matching the id 
    /// </summary> 
    T GetById(int id); 

    /// <summary> 
    /// Get an item or itens matching the Expression including opcional parameters 
    /// </summary> 
    IList<T> Get(Expression<Func<T, bool>> filter = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, string includeProperties = ""); 

    /// <summary> 
    /// Get an item matching to prediate 
    /// </summary> 
    //T Get(Func<T, bool> predicate); 


    /// <summary> 
    /// Get all the itens matching to prediate 
    /// </summary> 
    IList<T> GetAll(Func<T, bool> predicate); 


    ///// <summary> 
    ///// Get all the element of this repository 
    ///// </summary> 
    ///// <returns>Entities list</returns> 
    IList<T> GetAll(); 


    /// <summary> 
    /// Allow to send Linq queries to the entity 
    /// </summary> 
    IQueryable<T> Query { get; } 


    /// <summary> 
    /// Saves the pending changes back into the DataContext. 
    /// </summary> 
    void Save(); 
} 

क्वेरी का कार्यान्वयन:

public class Repository<T> : IRepository<T> where T : class 
{ 
    protected DbContext _dataContext; 
    protected DbSet<T> _dbSet; 

    public virtual IQueryable<T> Query 
    { 
     get 
     { 
      return _dbSet; 
     } 
    } 
} 
+0

'blogPostQuery' किस प्रकार का है? या शायद मुझे पूछना चाहिए: '_blogPostRepository.Query' संपत्ति में क्या होता है? यदि आप मूल ईएफ क्वेरी वापस कर देंगे तो शायद आपके पास शून्य संदर्भ अपवाद नहीं होगा। –

+0

हाय धन्यवाद। blogPostQuery टाइप आईआरपीओसेटरी _blogPostRepository है; जहां मेरे भंडार में मेरे पास ईएफ पर सभी ऑपरेशन हैं जैसे अटैच एक्सपैच अपडेट जोड़ें लेकिन इसमें शामिल नहीं है :( – Patrick

+0

आपको मूल 'IQueryable' को EF से वापस करना होगा, अन्यथा आंतरिक क्वेरी हमेशा * सभी * रिकॉर्ड वापस कर देगी। आप नहीं कर सकते अनुमानों या भविष्यवाणियों का उपयोग करें जिन्हें एसक्यूएल में वापस अनुवादित किया गया है और पेलोड को कम किया गया है और आप एकाधिक रिपॉजिटरीज़ से क्वेरी को एक तरीके से लिख नहीं सकते हैं, जिस तरह से एक SQL क्वेरी उत्पन्न होती है। और इसमें 'शामिल' नहीं है, नहीं 'AsNoTracking'। एक बड़े पैमाने पर क्वेरी परिणाम के लिए LINQ-to-ऑब्जेक्ट्स को लागू करना, इसलिए शून्य ऑब्जेक्ट संदर्भ (एक 'bp.BlogTags')। SQL में यह कोई समस्या नहीं होगी। –

उत्तर

5

मुख्य क्वेरी के भीतर निकाय लोड करने के लिए, (इस प्रक्रिया eager loading कहा जाता है), तो आप उपयोग कर सकते हैं Include() method और एक अभिव्यक्ति के रूप में अपना संग्रह पास करें। जब से तुम ToList या Single या FistOrDefault तरीकों फोन

var result = _blogPostRepository.Query 
           .Where(b => b.UrlSlug.Equals(urlSlug)) 
           .Include(b => b.Tags) 
           .Select(bp => new BlogPostGetByUrlSlugDto 
           { 
            Id = bp.Id, 
            Title = bp.Title, 
            Category = bp.BlogCategory.Name, 
            Color = bp.BlogCategory.Color, 
            UrlSlug = bp.UrlSlug, 
            Description = bp.Description, 
            Tags = bp.Tags.Select(t => new BlogTagGetByPostIdDto 
                 { 
                  Name = t.Name, 
                  UrlSlug = t.UrlSlug 
                 }) 
           }) 
           .FirstOrDefault(); 

return result; 

: इस तरह,

using System.Data.Entity; 

नमूने के लिए कुछ प्रयास करें:

इकाई की रूपरेखा के कुछ एक्सटेंशन का उपयोग करने के लिए निम्न नाम स्थान जोड़ने के लिए याद , यह डेटाबेस में क्वेरी निष्पादित करेगा। अपने कोड में, आप ToList() पर कॉल करते हैं और यह डेटाबेस में क्वेरी निष्पादित करेगा और टैग के लिए प्रत्येक क्वेरी (आलसी लोडिंग) निष्पादित करेगा।

इस लेख को Earger/Lazy लोडिंग के साथ कैसे नेतृत्व करें इस बारे में और जानने के लिए पढ़ें। http://msdn.microsoft.com/en-us/data/jj574232.aspx

+0

हाय धन्यवाद! आपकी राय में सबसे अच्छा विकल्प क्या है? स्मृति में निष्पादित करने के लिए Tolist() के साथ या डेटाबेस में निष्पादित किए बिना? – Patrick

+0

ToList डेटाबेस में निष्पादित करेगा और जो भी आप ToList के बाद करते हैं, यह स्मृति पर होगा। मुझे लगता है कि बेहतर होगा कि आप शामिल विधि का उपयोग करके टैग लोड करने का प्रयास करें और इसे 'फर्स्टऑर्डडिफॉल्ट' (जिसे कोई रजिस्टर नहीं मिला है, जिसे शून्य नहीं है) को कॉललिस्ट और सिंगल को कॉल करने के बजाय कॉल करें। –

+0

मेरे पास "शामिल नहीं है" की पहुंच नहीं है क्योंकि मैं एक रिपोजिटरी का उपयोग करता हूं जो इंटरफ़ेस IQueryable क्वेरी का उपयोग करता है {get; } BlogPostQuery चर के लिए। – Patrick

1

आप IQueryable साथ .Include उपयोग करने के लिए सक्षम होना चाहिए, लेकिन आप

using System.Data.Entity; 

जोड़ना चाहिए क्योंकि यह एक IQueryable विस्तार विधि है।

विधि विनिर्देश: DbExtensions.Include Method


कि इसके अलावा, आप अगर BlogCategory हो सकता है अशक्त की जांच होनी चाहिए, यदि यह मामला है कि आप अपने चयन में इसके साथ सौदा करने की आवश्यकता है, अन्यथा यह मान शून्य हो जाएगा और त्रुटि को फेंक दें क्योंकि आप किसी नल ऑब्जेक्ट की संपत्ति तक पहुंचने का प्रयास कर रहे हैं।

कुछ की तरह:

public BlogPostGetByUrlSlugDto GetByUrlSlug(string urlSlug) 
{ 
    var blogPostQuery = _blogPostRepository.Query; 

    return blogPostQuery 
       .Where(b => b.UrlSlug.Equals(urlSlug)) 
       .Include(b => b.Tags) 
       .Select(bp => new BlogPostGetByUrlSlugDto 
       { 
        Id = bp.Id, 
        Title = bp.Title, 
        Category = bp.BlogCategory == null ? string.Empty : bp.BlogCategory.Name, 
        Color = bp.BlogCategory == null ? string.Empty : bp.BlogCategory.Color, 
        UrlSlug = bp.UrlSlug, 
        Description = bp.Description, 
        Tags = bp.BlogTags.Select(t => new BlogTagGetByPostIdDto 
             { 
              Name = t.Name, 
              UrlSlug = t.UrlSlug 
             }) 
             .ToList() 
       }) 
       .FirstOrDefault(); 
} 
1

बदलें Tags इस के लिए BlogPostGetByUrlSlugDto में संग्रह (आभासी कीवर्ड आवश्यक है):

public virtual ICollection<BlogTagGetByPostIdDto> Tags { get; set; } 

यह लेज़ी लोड हो रहा है काम करने के लिए आवश्यक है। BlogTagGetByPostIdDto वर्ग भी एक प्राथमिक कुंजी की जरूरत है, तो यह करने के लिए बदल:

public class BlogTagGetByPostIdDto 
{ 
    [Key] 
    public string Name { get; set; } 
    public string UrlSlug { get; set; } 
} 

आप नाम अनन्य होना नहीं करना चाहते हैं, तो इस वर्ग के लिए एक आईडी प्रॉपर्टी जोड़ते हैं। जब आपने अब BlogPostGetByUrlSlugDto ऑब्जेक्ट पुनर्प्राप्त किया है, और आप Tags संपत्ति का उपयोग करते हैं, तो यह इस ऑब्जेक्ट से जुड़े टैग पुनर्प्राप्त करेगा।

संबंधित मुद्दे