protected override object[] Select(string entityName, IEnumerable <FilterCondition> filters, int fetchCount, int firstRowOffset, bool fillReferences, bool filterReferences, IDbConnection connection) { if (!m_entities.HasEntity(entityName)) { throw new EntityNotFoundException(entityName); } UpdateIndexCacheForType(entityName); //var genType = typeof(List<>).MakeGenericType(objectType); //var items = (System.Collections.IList)Activator.CreateInstance(genType); var items = new List <object>(); bool tableDirect; SqlEntityInfo entity = m_entities[entityName]; var isDynamicEntity = entity is DynamicEntityInfo; var bConnectionIsNew = connection == null; if (connection == null) { connection = GetConnection(false); } SqlCommand command = null; if (UseCommandCache) { Monitor.Enter(CommandCache); } try { OnBeforeSelect(m_entities[entityName], filters, fillReferences); var start = DateTime.Now; command = GetSelectCommand <SqlCommand, SqlParameter>(entityName, filters, firstRowOffset, fetchCount, out tableDirect); command.Connection = connection as SqlConnection; int searchOrdinal = -1; //ResultSetOptions options = ResultSetOptions.Scrollable; object matchValue = null; string matchField = null; using (var results = command.ExecuteReader(CommandBehavior.Default)) { if (results.HasRows) { var ordinals = GetOrdinals(entityName, results); ReferenceAttribute[] referenceFields = null; int currentOffset = 0; if (matchValue != null) { // convert enums to an int, else the .Equals later check will fail // this feels a bit kludgey, but for now it's all I can think of if (matchValue.GetType().IsEnum) { matchValue = (int)matchValue; } if (searchOrdinal < 0) { searchOrdinal = results.GetOrdinal(matchField); } } // autofill references if desired if (referenceFields == null) { referenceFields = Entities[entityName].References.ToArray(); } while (results.Read()) { if (currentOffset < firstRowOffset) { currentOffset++; continue; } object item = null; object rowPK = null; if (isDynamicEntity) { var dynamic = new DynamicEntity(entity as DynamicEntityInfo); foreach (var pair in ordinals) { if (entity.Fields[pair.Key].DataType == DbType.Object) { if (entity.Deserializer == null) { throw new MissingMethodException( string.Format("The field '{0}' requires a custom serializer/deserializer method pair in the '{1}' Entity", pair.Key, entityName)); } dynamic[pair.Key] = entity.Deserializer(dynamic, pair.Key, results[pair.Value]); } else { dynamic[pair.Key] = results[pair.Value]; } } item = dynamic; } else if (entity.CreateProxy == null) { if (entity.DefaultConstructor == null) { item = Activator.CreateInstance(entity.EntityType); } else { item = entity.DefaultConstructor.Invoke(null); } foreach (var field in Entities[entityName].Fields) { var value = results[field.FieldName]; if (value != DBNull.Value) { if (field.DataType == DbType.Object) { if (entity.Deserializer == null) { throw new MissingMethodException( string.Format("The field '{0}' requires a custom serializer/deserializer method pair in the '{1}' Entity", field.FieldName, entityName)); } var @object = entity.Deserializer.Invoke(item, field.FieldName, value); field.PropertyInfo.SetValue(item, @object, null); } else if (field.IsRowVersion) { // sql stores this an 8-byte array field.PropertyInfo.SetValue(item, BitConverter.ToInt64((byte[])value, 0), null); } else if (field.PropertyInfo.PropertyType.UnderlyingTypeIs <TimeSpan>()) { // SQL Compact doesn't support Time, so we're convert to ticks in both directions var valueAsTimeSpan = new TimeSpan((long)value); field.PropertyInfo.SetValue(item, valueAsTimeSpan, null); } else { field.PropertyInfo.SetValue(item, value, null); } } //Check if it is reference key to set, not primary. ReferenceAttribute attr = referenceFields.Where( x => x.ReferenceField == field.FieldName).FirstOrDefault(); if (attr != null) { rowPK = value; } if (field.IsPrimaryKey) { rowPK = value; } } } else { item = entity.CreateProxy(results, ordinals); } if ((fillReferences) && (referenceFields.Length > 0)) { FillReferences(item, rowPK, referenceFields, false, filterReferences, connection); } items.Add(item); if ((fetchCount > 0) && (items.Count >= fetchCount)) { break; } } } } OnAfterSelect(m_entities[entityName], filters, fillReferences, DateTime.Now.Subtract(start), command.CommandText); } finally { if ((!UseCommandCache) && (command != null)) { command.Dispose(); } if (UseCommandCache) { Monitor.Exit(CommandCache); } FlushReferenceTableCache(); if (bConnectionIsNew) { DoneWithConnection(connection, false); } } return(items.ToArray()); }
protected override object[] Select(string entityName, IEnumerable <FilterCondition> filters, int fetchCount, int firstRowOffset, bool fillReferences, bool filterReferences, IDbConnection connection) { if (!m_entities.HasEntity(entityName)) { throw new EntityNotFoundException(entityName); } UpdateIndexCacheForType(entityName); //var genType = typeof(List<>).MakeGenericType(objectType); //var items = (System.Collections.IList)Activator.CreateInstance(genType); var items = new List <object>(); bool tableDirect; SqlEntityInfo entity = m_entities[entityName]; var isDynamicEntity = entity is DynamicEntityInfo; if (connection == null) { connection = GetConnection(false); } SqlCeCommand command = null; if (UseCommandCache) { Monitor.Enter(CommandCache); } try { CheckPrimaryKeyIndex(entityName); OnBeforeSelect(entity, filters, fillReferences); var start = DateTime.Now; command = GetSelectCommand <SqlCeCommand, SqlCeParameter>(entityName, filters, firstRowOffset, fetchCount, out tableDirect); command.Connection = connection as SqlCeConnection; int searchOrdinal = -1; ResultSetOptions options = ResultSetOptions.Scrollable; object matchValue = null; string matchField = null; bool primarykeyfilter = false; if (tableDirect) // use index { if ((filters != null) && (filters.Count() > 0)) { var filter = filters.First(); matchValue = filter.Value ?? DBNull.Value; matchField = filter.FieldName; var sqlfilter = filter as SqlFilterCondition; if ((sqlfilter != null) && (sqlfilter.PrimaryKey)) { primarykeyfilter = true; } } // we need to ensure that the search value does not exceed the length of the indexed // field, else we'll get an exception on the Seek call below var indexInfo = GetIndexInfo(command.IndexName); if (indexInfo != null) { if (indexInfo.MaxCharLength > 0) { var value = (string)matchValue; if (value.Length > indexInfo.MaxCharLength) { matchValue = value.Substring(0, indexInfo.MaxCharLength); } } } } using (var results = command.ExecuteResultSet(options)) { if (results.HasRows) { var ordinals = GetOrdinals(entityName, results); ReferenceAttribute[] referenceFields = null; int currentOffset = 0; if (matchValue != null) { // convert enums to an int, else the .Equals later check will fail // this feels a bit kludgey, but for now it's all I can think of if (matchValue.GetType().IsEnum) { matchValue = (int)matchValue; } if (primarykeyfilter) { searchOrdinal = ordinals[m_entities[entityName].Fields.KeyField.FieldName]; } else if (searchOrdinal < 0) { searchOrdinal = ordinals[matchField]; } if (tableDirect) { results.Seek(DbSeekOptions.FirstEqual, new object[] { matchValue }); } } // autofill references if desired if (referenceFields == null) { referenceFields = entity.References.ToArray(); } while (results.Read()) { if (currentOffset < firstRowOffset) { currentOffset++; continue; } if (tableDirect && (matchValue != null)) { // if we have a match value, we'll have seeked to the first match above // then at this point the first non-match means we have no more matches, so // we can exit out once we hit the first non-match. // For string we want a case-insensitive search, so it's special-cased here if (matchValue is string) { if (string.Compare((string)results[searchOrdinal], (string)matchValue, true) != 0) { break; } } else { if (!results[searchOrdinal].Equals(matchValue)) { break; } } } object item = null; object rowPK = null; if (isDynamicEntity) { var dynamic = new DynamicEntity(entity as DynamicEntityInfo); foreach (var pair in ordinals) { if (entity.Fields[pair.Key].DataType == DbType.Object) { if (entity.Deserializer == null) { throw new MissingMethodException( string.Format("The field '{0}' requires a custom serializer/deserializer method pair in the '{1}' Entity", pair.Key, entityName)); } dynamic[pair.Key] = entity.Deserializer(dynamic, pair.Key, results[pair.Value]); } else { dynamic[pair.Key] = results[pair.Value]; } } item = dynamic; } else if (entity.CreateProxy == null) { if (entity.DefaultConstructor == null) { item = Activator.CreateInstance(entity.EntityType); } else { item = entity.DefaultConstructor.Invoke(null); } foreach (var field in entity.Fields) { var value = results[ordinals[field.FieldName]]; if (value != DBNull.Value) { if (field.DataType == DbType.Object) { if (entity.Deserializer == null) { throw new MissingMethodException( string.Format("The field '{0}' requires a custom serializer/deserializer method pair in the '{1}' Entity", field.FieldName, entityName)); } var @object = entity.Deserializer.Invoke(item, field.FieldName, value); field.PropertyInfo.SetValue(item, @object, null); } else if (field.IsRowVersion) { // sql stores this an 8-byte array field.PropertyInfo.SetValue(item, BitConverter.ToInt64((byte[])value, 0), null); } else if (field.PropertyInfo.PropertyType.UnderlyingTypeIs <TimeSpan>()) { // SQL Compact doesn't support Time, so we're convert to ticks in both directions var valueAsTimeSpan = new TimeSpan((long)value); field.PropertyInfo.SetValue(item, valueAsTimeSpan, null); } else { field.PropertyInfo.SetValue(item, value, null); } } //Check if it is reference key to set, not primary. ReferenceAttribute attr = referenceFields.Where( x => x.ReferenceField == field.FieldName).FirstOrDefault(); if (attr != null) { rowPK = value; } if (field.IsPrimaryKey) { rowPK = value; } } } else { item = entity.CreateProxy.Invoke(results, ordinals); } if ((fillReferences) && (referenceFields.Length > 0)) { if (entity.Fields.KeyFields.Count == 1) { rowPK = entity.Fields.KeyField.PropertyInfo.GetValue(item, null); //FillReferences(item, rowPK, referenceFields, true); FillReferences(item, rowPK, referenceFields, false, fillReferences, connection); } } items.Add(item); if ((fetchCount > 0) && (items.Count >= fetchCount)) { break; } } } } OnAfterSelect(entity, filters, fillReferences, DateTime.Now.Subtract(start), command.CommandText); } finally { if ((!UseCommandCache) && (command != null)) { command.Dispose(); } if (UseCommandCache) { Monitor.Exit(CommandCache); } FlushReferenceTableCache(); DoneWithConnection(connection, false); } return(items.ToArray()); }