Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Data.Entity / System / Data / Objects / ObjectResult_TResultType.cs
1 //---------------------------------------------------------------------
2 // <copyright file="ObjectResult.cs" company="Microsoft">
3 //      Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //
6 // @owner       Microsoft
7 // @backupowner Microsoft
8 //---------------------------------------------------------------------
9
10 namespace System.Data.Objects
11 {
12     using System;
13     using System.Collections;
14     using System.Collections.Generic;
15     using System.Collections.ObjectModel;
16     using System.ComponentModel;
17     using System.Data;
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;
26         
27     /// <summary>
28     /// This class implements IEnumerable of T and IDisposable. Instance of this class
29     /// is returned from ObjectQuery&lt;T&gt;.Execute method.
30     /// </summary>
31     [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
32     public sealed class ObjectResult<T> : ObjectResult, IEnumerable<T>
33     {
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;
42
43         internal ObjectResult(Shaper<T> shaper, EntitySet singleEntitySet, TypeUsage resultItemType)
44             : this(shaper, singleEntitySet, resultItemType, true)
45         {
46         }
47
48         internal ObjectResult(Shaper<T> shaper, EntitySet singleEntitySet, TypeUsage resultItemType, bool readerOwned)
49             : this(shaper, singleEntitySet, resultItemType, readerOwned, null, null)
50         {
51         }
52
53         internal ObjectResult(Shaper<T> shaper, EntitySet singleEntitySet, TypeUsage resultItemType, bool readerOwned, NextResultGenerator nextResultGenerator, Action<object, EventArgs> onReaderDispose)
54         {
55             _shaper = shaper;
56             _reader = _shaper.Reader;
57             _singleEntitySet = singleEntitySet;
58             _resultItemType = resultItemType;
59             _readerOwned = readerOwned;
60             _nextResultGenerator = nextResultGenerator;
61             _onReaderDispose = onReaderDispose;
62         }
63
64         private void EnsureCanEnumerateResults()
65         {
66             if (null == _shaper)
67             {
68                 // Enumerating more than once is not allowed.
69                 throw EntityUtil.CannotReEnumerateQueryResults();
70             }
71         }
72
73         /// <summary>
74         /// Returns an enumerator that iterates through the collection. 
75         /// </summary>
76         public IEnumerator<T> GetEnumerator()
77         {
78             EnsureCanEnumerateResults();
79
80             Shaper<T> shaper = _shaper;
81             _shaper = null;
82             IEnumerator<T> result = shaper.GetEnumerator();
83             return result;
84         }
85
86         /// <summary>
87         /// Performs tasks associated with freeing, releasing, or resetting resources. 
88         /// </summary>
89         public override void Dispose()
90         {
91             DbDataReader reader = _reader;
92             _reader = null;
93             _nextResultGenerator = null;
94
95             if (null != reader && _readerOwned)
96             {
97                 reader.Dispose();
98                 if (_onReaderDispose != null)
99                 {
100                     _onReaderDispose(this, new EventArgs());
101                     _onReaderDispose = null;
102                 }
103             }
104             if (_shaper != null)
105             {
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)
109                 {
110                     _shaper.Context.ReleaseConnection();
111                 }
112                 _shaper = null;
113             }
114         }
115
116         internal override IEnumerator GetEnumeratorInternal()
117         {
118             return ((IEnumerable<T>)this).GetEnumerator();
119         }
120
121         internal override IList GetIListSourceListInternal()
122         {
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.
127
128             if (_cachedBindingList == null)
129             {
130                 EnsureCanEnumerateResults();
131
132                 bool forceReadOnly = this._shaper.MergeOption == MergeOption.NoTracking;
133                 _cachedBindingList = ObjectViewFactory.CreateViewForQuery<T>(this._resultItemType, this, this._shaper.Context, forceReadOnly, this._singleEntitySet);
134             }
135
136             return _cachedBindingList;
137         }
138
139         internal override ObjectResult<TElement> GetNextResultInternal<TElement>()
140         {
141             return null != _nextResultGenerator ? _nextResultGenerator.GetNextResult<TElement>(_reader) : null;
142         }
143
144         public override Type ElementType
145         {
146             get { return typeof(T); }
147         }
148     }
149 }