using Ant.Common; using Ant.Core; using Ant.Data; using Ant.Descriptors; using Ant.Mapper; using Ant.ORM; using Ant.Query.Mapping; using Ant.Utility; using System; using System.Collections; using System.Collections.Generic; using System.Data; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Text; using System.Threading; namespace Ant.ORM { class ORMInternalSqlQuery : IEnumerable, IEnumerable { DataAccess db; string _sql; DbParam[] _parameters; public ORMInternalSqlQuery(DataAccess dbContext, string sql, DbParam[] parameters) { this.db = dbContext; this._sql = sql; this._parameters = parameters; } public IEnumerator GetEnumerator() { return new QueryEnumerator(this); } IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } struct QueryEnumerator : IEnumerator { ORMInternalSqlQuery _internalSqlQuery; IDataReader _reader; IObjectActivator _objectActivator; T _current; bool _hasFinished; bool _disposed; public QueryEnumerator(ORMInternalSqlQuery internalSqlQuery) { this._internalSqlQuery = internalSqlQuery; this._reader = null; this._objectActivator = null; this._current = default(T); this._hasFinished = false; this._disposed = false; } public T Current { get { return this._current; } } object IEnumerator.Current { get { return this._current; } } public bool MoveNext() { if (this._hasFinished || this._disposed) return false; if (this._reader == null) { this.Prepare(); } if (this._reader.Read()) { this._current = (T)this._objectActivator.CreateInstance(this._reader); return true; } else { this._reader.Close(); this._internalSqlQuery.db.Close(); this._current = default(T); this._hasFinished = true; return false; } } public void Dispose() { if (this._disposed) return; if (this._reader != null) { if (!this._reader.IsClosed) this._reader.Close(); this._reader.Dispose(); this._reader = null; } if (!this._hasFinished) { this._internalSqlQuery.db.Close(); this._hasFinished = true; } this._current = default(T); this._disposed = true; } public void Reset() { throw new NotSupportedException(); } void Prepare() { Type type = typeof(T); if (AntUtils.IsMapType(type)) { MappingField mf = new MappingField(type, 0); this._objectActivator = mf.CreateObjectActivator(); this._reader = this._internalSqlQuery.db.ExecuteReader(this._internalSqlQuery._sql, this._internalSqlQuery._parameters, CommandBehavior.Default, CommandType.Text); return; } this._reader = this._internalSqlQuery.db.ExecuteReader(this._internalSqlQuery._sql, this._internalSqlQuery._parameters, CommandBehavior.Default, CommandType.Text); this._objectActivator = GetObjectActivator(type, this._reader); } static ObjectActivator GetObjectActivator(Type type, IDataReader reader) { List caches; if (!ObjectActivatorCache.TryGetValue(type, out caches)) { if (!Monitor.TryEnter(type)) { return CreateObjectActivator(type, reader); } try { caches = ObjectActivatorCache.GetOrAdd(type, new List(1)); } finally { Monitor.Exit(type); } } CacheInfo cache = TryGetCacheInfoFromList(caches, reader); if (cache == null) { lock (caches) { cache = TryGetCacheInfoFromList(caches, reader); if (cache == null) { ObjectActivator activator = CreateObjectActivator(type, reader); cache = new CacheInfo(activator, reader); caches.Add(cache); } } } return cache.ObjectActivator; } static ObjectActivator CreateObjectActivator(Type type, IDataReader reader) { EntityConstructorDescriptor constructorDescriptor = EntityConstructorDescriptor.GetInstance(type.GetConstructor(Type.EmptyTypes)); EntityMemberMapper mapper = constructorDescriptor.GetEntityMemberMapper(); Func instanceCreator = constructorDescriptor.GetInstanceCreator(); List memberSetters = PrepareValueSetters(type, reader, mapper); return new ObjectActivator(instanceCreator, null, null, memberSetters, null); } static List PrepareValueSetters(Type type, IDataReader reader, EntityMemberMapper mapper) { List memberSetters = new List(reader.FieldCount); MemberInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty); MemberInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetField); List members = new List(properties.Length + fields.Length); members.AddRange(properties); members.AddRange(fields); for (int i = 0; i < reader.FieldCount; i++) { string name = reader.GetName(i); var member = members.Where(a => a.Name == name).FirstOrDefault(); if (member == null) { member = members.Where(a => string.Equals(a.Name, name, StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); if (member == null) continue; } IMRM mMapper = mapper.GetMemberMapper(member); if (mMapper == null) continue; MappingMemberBinder memberBinder = new MappingMemberBinder(mMapper, i); memberSetters.Add(memberBinder); } return memberSetters; } static CacheInfo TryGetCacheInfoFromList(List caches, IDataReader reader) { CacheInfo cache = null; for (int i = 0; i < caches.Count; i++) { var item = caches[i]; if (item.IsTheSameFields(reader)) { cache = item; break; } } return cache; } static readonly System.Collections.Concurrent.ConcurrentDictionary> ObjectActivatorCache = new System.Collections.Concurrent.ConcurrentDictionary>(); } public class CacheInfo { Tuple[] _readerFields; ObjectActivator _objectActivator; public CacheInfo(ObjectActivator activator, IDataReader reader) { int fieldCount = reader.FieldCount; var readerFields = new Tuple[fieldCount]; for (int i = 0; i < fieldCount; i++) { readerFields[i] = new Tuple(reader.GetName(i), reader.GetFieldType(i)); } this._readerFields = readerFields; this._objectActivator = activator; } public ObjectActivator ObjectActivator { get { return this._objectActivator; } } public bool IsTheSameFields(IDataReader reader) { Tuple[] readerFields = this._readerFields; int fieldCount = reader.FieldCount; if (fieldCount != readerFields.Length) return false; for (int i = 0; i < fieldCount; i++) { Tuple tuple = readerFields[i]; if (reader.GetFieldType(i) != tuple.Item2 || reader.GetName(i) != tuple.Item1) { return false; } } return true; } } } }