Olaj
Olaj

Reputation: 1782

Part of LINQ query to seperate method (EF Core)

I guess this has been asked before but i don't find any good examples. I have this query.

series = await query
    .GroupBy(o => new { o.AddedDate.Date.Month, o.AddedDate.Date.Year })
    .Select(g => new DateLineGraphItem 
        { Legend = new DateTime(g.Key.Year, g.Key.Month, 1), Number = g.Count() })
    .ToListAsync();

Everything is the same all the time except that my DB has different names for all the "AddedDate" column and i'm trying to figure out how i can break this out into it's own method, something like this.

List<DateLineGraphItem> series = GroupByAndSelect("AddedDate")
List<DateLineGraphItem> series = GroupByAndSelect("CreatedDate")

Do i have to use Expressions and Predicates and all that or it is possible to do in some simple manner?

Upvotes: 3

Views: 302

Answers (2)

Ivan Stoev
Ivan Stoev

Reputation: 205579

Do i have to use Expressions

It's always better to use expressions (the whole LINQ is based on that concept) than magic strings. The only problem is that there is no out of the box solution for composing expressions from other expressions, so you need to write your own or use 3rd party packages.

From the other side, the nameof operator eliminates most of the string drawbacks. And EF Core provides a handy method called EF.Property for simple scenarios like this.

So if the method contains string propertyName argument which points to direct property of type DateTime, you can simply replace the o.AddedDate with EF.Property<DateTime>(o, propertyName), e.g.

series = await query
    .GroupBy(o => new { EF.Property<DateTime>(o, propertyName).Date.Month, EF.Property<DateTime>(o, propertyName).Date.Year })
    .Select(g => new DateLineGraphItem 
        { Legend = new DateTime(g.Key.Year, g.Key.Month, 1), Number = g.Count() })
    .ToListAsync();

Upvotes: 3

ElettroAle
ElettroAle

Reputation: 139

I had the same problem. You may extend your entity class using an interface which contains a DateTime Field, like this:

    public class EntityDb1 : IDatedEntity
    {
        public DateTime AddedDate { get; set; }

        public DateTime MyDate => AddedDate;
    }
    public class EntityDb2 : IDatedEntity
    {
        public DateTime CreatedDate { get; set; }

        public DateTime MyDate => CreatedDate;
    }

    public interface IDatedEntity
    {
        DateTime MyDate{ get; }
    }

Then execute the query

        public class Test
        {
            public static async Task<IEnumerable<DateLineGraphItem>> ExecuteQuery(IQueryable<IDatedEntity> entityList)
            {
                return await entityList
                    .GroupBy(o =>new { o.MyDate.Date.Month, o.MyDate.Date.Year })
                    .Select(g => new DateLineGraphItem(){ Legend = new DateTime(g.Key.Year, g.Key.Month, 1), Number = g.Count() })
                    .ToListAsync();
            }
        }

        public class DateLineGraphItem
        {
            public DateTime Legend { get; set; }
            public int Number { get; set; }
        }

Upvotes: 0

Related Questions