Couldn't Select<T> return IEnumerable<T> instead of T[]

Oct 4, 2012 at 2:11 PM

Hi Chris

Have you considered using yield return and let Select<T> return IEnumerable<T> instead of T[]. It would of course have to be implemented all the way through, i.e. all the various Select methods should avoid returning arrays and use IEnumerables instead.

The advantage would be, that you can make selects that potentially returns millions of rows, but still get to the first row quickly.

I know I can use fetchCount and firstRowOffset to page through the results, but using large values of firstRowOffset are slow and paging is sort of clumsy in many situations.

As I read the code it wouldn't be to difficult to implement - I might even volunteer, if you agree.

Best regards, Kasper

Coordinator
Oct 4, 2012 at 2:26 PM

Agreed, I think it would be a good addition/modification.

Oct 5, 2012 at 9:25 AM
Edited Oct 5, 2012 at 1:32 PM

Hi Chris

One approach is to simply change the existing signatures on the Select/Fetch methods on IDataStore:

        IEnumerable<T> Select<T>() where T : new();
        IEnumerable<T> Select<T>(bool fillReferences) where T : new();
        IEnumerable<T> Select<T>(string searchFieldName, object matchValue) where T : new();
        IEnumerable<T> Select<T>(string searchFieldName, object matchValue, bool fillReferences) where T : new();
        IEnumerable<T> Select<T>(IEnumerable<FilterCondition> filters) where T : new();
        IEnumerable<T> Select<T>(IEnumerable<FilterCondition> filters, bool fillReferences) where T : new();
        IEnumerable<object> Select(Type entityType);
        IEnumerable<object> Select(Type entityType, bool fillReferences);
        IEnumerable<T> Select<T>(Func<T, bool> selector) where T : new();
        IEnumerable<DynamicEntity> Select(string entityName);

        IEnumerable<T> Fetch<T>(int fetchCount) where T : new();
        IEnumerable<T> Fetch<T>(int fetchCount, int firstRowOffset) where T : new();
        IEnumerable<T> Fetch<T>(int fetchCount, int firstRowOffset, string sortField) where T : new();
        IEnumerable<T> Fetch<T>(int fetchCount, int firstRowOffset, string sortField, FieldSearchOrder sortOrder, FilterCondition filter, bool fillReferences)
            where T : new();

This will introduce a little bit of a hazzle to any exiting users wanting to upgrade, but it may be acceptable and it will keep the interface simple. Alternatively, I can add a new set of LazySelect/LazyFetch methods, to allow the user to opt in. What do you think is the better approach?

If you prefer the second approach, I'll introduce the following new methods to IDataStore instead:

        IEnumerable<T> LazySelect<T>() where T : new();
        IEnumerable<T> LazySelect<T>(bool fillReferences) where T : new();
        IEnumerable<T> LazySelect<T>(string searchFieldName, object matchValue) where T : new();
        IEnumerable<T> LazySelect<T>(string searchFieldName, object matchValue, bool fillReferences) where T : new();
        IEnumerable<T> LazySelect<T>(IEnumerable<FilterCondition> filters) where T : new();
        IEnumerable<T> LazySelect<T>(IEnumerable<FilterCondition> filters, bool fillReferences) where T : new();
        IEnumerable<object> LazySelect(Type entityType);
        IEnumerable<object> LazySelect(Type entityType, bool fillReferences);
        IEnumerable<T> LazySelect<T>(Func<T, bool> selector) where T : new();
        IEnumerable<DynamicEntity> LazySelect(string entityName);
        IEnumerable<T> LazyFetch<T>(int fetchCount) where T : new();
        IEnumerable<T> LazyFetch<T>(int fetchCount, int firstRowOffset) where T : new();
        IEnumerable<T> LazyFetch<T>(int fetchCount, int firstRowOffset, string sortField) where T : new();
        IEnumerable<T> LazyFetch<T>(int fetchCount, int firstRowOffset, string sortField, FieldSearchOrder sortOrder, FilterCondition filter, bool fillReferences)
            where T : new();

And then implement the exisiting Select/Fetch methods as simply call through to these, i.e.:

        public virtual T[] Select<T>() where T : new()
        {
            return LazySelect<T>().ToArray();
        }

I think I prefer the first approach, but then I don't have a lot of code that already depends on Select/Fetch returning arrays. What do you prefer?

Best regards, Kasper

Coordinator
Oct 5, 2012 at 2:44 PM

I prefer just replacing the existing Select and Fetch commands.  Yes, it breaks the interface, but most code for arrays should just work with IEnumerable, and code that doesn't should be easy enough to fix up.  I'd much rather that than cluttering the object model needlessly, and sometimes breaking things is good.

Oct 5, 2012 at 5:56 PM

Okay. See patch 12987.

Coordinator
Oct 5, 2012 at 7:04 PM

Patch applied.