1 //---------------------------------------------------------------------
2 // <copyright file="ObjectResult.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupowner Microsoft
8 //---------------------------------------------------------------------
10 namespace System.Data.Objects
13 using System.Collections;
14 using System.Collections.Generic;
15 using System.Collections.ObjectModel;
16 using System.ComponentModel;
18 using System.Data.Common;
19 using System.Data.Common.Utils;
20 using System.Data.Metadata.Edm;
21 using System.Data.Mapping;
22 using System.Data.Objects.DataClasses;
23 using System.Diagnostics;
24 using System.Linq.Expressions;
25 using System.Data.Common.Internal.Materialization;
28 /// This class implements IEnumerable of T and IDisposable. Instance of this class
29 /// is returned from ObjectQuery<T>.Execute method.
31 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
32 public sealed class ObjectResult<T> : ObjectResult, IEnumerable<T>
34 private Shaper<T> _shaper;
35 private DbDataReader _reader;
36 private readonly EntitySet _singleEntitySet;
37 private readonly TypeUsage _resultItemType;
38 private readonly bool _readerOwned;
39 private IBindingList _cachedBindingList;
40 private NextResultGenerator _nextResultGenerator;
41 private Action<object, EventArgs> _onReaderDispose;
43 internal ObjectResult(Shaper<T> shaper, EntitySet singleEntitySet, TypeUsage resultItemType)
44 : this(shaper, singleEntitySet, resultItemType, true)
48 internal ObjectResult(Shaper<T> shaper, EntitySet singleEntitySet, TypeUsage resultItemType, bool readerOwned)
49 : this(shaper, singleEntitySet, resultItemType, readerOwned, null, null)
53 internal ObjectResult(Shaper<T> shaper, EntitySet singleEntitySet, TypeUsage resultItemType, bool readerOwned, NextResultGenerator nextResultGenerator, Action<object, EventArgs> onReaderDispose)
56 _reader = _shaper.Reader;
57 _singleEntitySet = singleEntitySet;
58 _resultItemType = resultItemType;
59 _readerOwned = readerOwned;
60 _nextResultGenerator = nextResultGenerator;
61 _onReaderDispose = onReaderDispose;
64 private void EnsureCanEnumerateResults()
68 // Enumerating more than once is not allowed.
69 throw EntityUtil.CannotReEnumerateQueryResults();
74 /// Returns an enumerator that iterates through the collection.
76 public IEnumerator<T> GetEnumerator()
78 EnsureCanEnumerateResults();
80 Shaper<T> shaper = _shaper;
82 IEnumerator<T> result = shaper.GetEnumerator();
87 /// Performs tasks associated with freeing, releasing, or resetting resources.
89 public override void Dispose()
91 DbDataReader reader = _reader;
93 _nextResultGenerator = null;
95 if (null != reader && _readerOwned)
98 if (_onReaderDispose != null)
100 _onReaderDispose(this, new EventArgs());
101 _onReaderDispose = null;
106 // This case includes when the ObjectResult is disposed before it
107 // created an ObjectQueryEnumeration; at this time, the connection can be released
108 if (_shaper.Context != null && _readerOwned)
110 _shaper.Context.ReleaseConnection();
116 internal override IEnumerator GetEnumeratorInternal()
118 return ((IEnumerable<T>)this).GetEnumerator();
121 internal override IList GetIListSourceListInternal()
123 // You can only enumerate the query results once, and the creation of an ObjectView consumes this enumeration.
124 // However, there are situations where setting the DataSource of a control can result in multiple calls to this method.
125 // In order to enable this scenario and allow direct binding to the ObjectResult instance,
126 // the ObjectView is cached and returned on subsequent calls to this method.
128 if (_cachedBindingList == null)
130 EnsureCanEnumerateResults();
132 bool forceReadOnly = this._shaper.MergeOption == MergeOption.NoTracking;
133 _cachedBindingList = ObjectViewFactory.CreateViewForQuery<T>(this._resultItemType, this, this._shaper.Context, forceReadOnly, this._singleEntitySet);
136 return _cachedBindingList;
139 internal override ObjectResult<TElement> GetNextResultInternal<TElement>()
141 return null != _nextResultGenerator ? _nextResultGenerator.GetNextResult<TElement>(_reader) : null;
144 public override Type ElementType
146 get { return typeof(T); }