如何在Entity Framework Core中按周分组?

时间:2017-03-08 15:20:09

标签: linq group-by .net-core entity-framework-core week-number

在Entity Framework 6中,我可以使用SqlFunctions.DatePart()方法:

var byWeek = data.GroupBy(x => SqlFunctions.DatePart("week", x.Date));

但是这些类(DbFunctionsSqlFunctions在实体框架核心中不可用)(reference)。

所以我的问题是如何在Entity Framework核心中按周分组?

3 个答案:

答案 0 :(得分:3)

我目前缺少功能的解决方法是

var firstMondayOfYear = this.GetFirstMondayOfYear(DateTime.Now.Year);
var entries =
    this.entitiesService.FindForLastMonths(this.CurrentUser.Id, 6)
        .GroupBy(x => ((int)(x.Date - firstMondayOfYear).TotalDays / 7))

函数GetFirstMondayOfYear

private DateTime GetFirstMondayOfYear(int year)
{
    var dt = new DateTime(year, 1, 1);
    while (dt.DayOfWeek != DayOfWeek.Monday)
    {
        dt = dt.AddDays(1);
    }

    return dt;
}

此分组给出当前年份的周数和前几年的负值。

稍后您可以使用此getter获取周名称:

public string WeekName
{
    get
    {
        var year = DateTime.Now.AddYears((int)Math.Floor(this.WeekNumber / 52.0)).Year;
        var weekNumber = this.WeekNumber % 52;
        while (weekNumber < 0)
        {
            weekNumber += 52;
        }

        return $"{year}, W{weekNumber}";
    }
}

答案 1 :(得分:1)

可以通过将日期部分SQL函数与DbFunctionAttribute包装在一起来使用它。 棘手的部分是告诉ef核心不要将datepart类型参数作为字符串处理。示例:

DbContext:

class Nav extends Component {
    constructor(props){
        super(props);

        ["showHideSubmenu"].forEach((method) => {
            this[method] = this[method].bind(this);
        });

        this.state = {
            navigation: {
                menu: [],
            },
            showSubmenu: -1,
        }
    }

    componentDidMount() {
        fetch('http:json_menuFIN.php')
            .then(response => response.json())
            .then(data =>{
                this.setState({navigation: data});                
            })
    }

    showHideSubmenu(key){
        this.setState({
            showSubmenu: key,
        });
    }
    render(){
        const renderMenu = items => {
            return (
                <ul className="list">
                    {items.map((i, key) => {
                        var icoJson;
                        if(i.ico){
                            icoJson = <Icon icon={i.ico} className={"ico-" + i.ico} />;
                        }
                        var firstMenu = i.fstmenu ? "first-menu" : "";
                        var secondMenu = i.sndmenu ? "second-menu" : "";
                        var classMn = i.fstmenu ? "mn-" : "";
                        var classSb = i.sndmenu ? "sb-" : "";
                        return (
                            <li className={`list__item ${firstMenu}${secondMenu}`} key={i.fsttitle + i.sndtitle + i.trdtitle}>
                                <a 
                                    href={i.URL} 
                                    className={`${classMn}${classSb}`+i.fsttitle}
                                    onClick={(key) => {
                                        if (i.fstmenu) { 
                                            this.showHideSubmenu(key);
                                        }
                                    }
                                >
                                        {icoJson}
                                        <span>{i.fsttitle}{i.sndtitle}{i.trdtitle}</span>
                                </a>
                                {i.menu && renderMenu(i.menu)}
                                {this.state.showSubmenu === key &&
                                    (
                                        <>
                                        {i.fstmenu && renderMenu(i.fstmenu)}
                                        {i.sndmenu && renderMenu(i.sndmenu)}
                                        </>
                                    )
                                }
                            </li>
                        )
                    })}
                </ul>
            )
        }
        return (
            <nav className="nav">
                <div className="menu">
                    {renderMenu(this.state.navigation.menu)}
                </div>
            </nav>
        )
    }
}

查询:

public int? DatePart(string datePartArg, DateTime? date) => throw new Exception();

public void OnModelCreating(DbModelBuilder modelBuilder) {
    var methodInfo = typeof(DbContext).GetRuntimeMethod(nameof(DatePart), new[] { typeof(string), typeof(DateTime) });
    modelBuilder
        .HasDbFunction(methodInfo)
        .HasTranslation(args => new SqlFunctionExpression(nameof(DatePart), typeof(int?), new[]
                {
                        new SqlFragmentExpression(args.ToArray()[0].ToString()),
                        args.ToArray()[1]
                }));
}

更多信息:https://github.com/aspnet/EntityFrameworkCore/issues/10404

答案 2 :(得分:0)

我碰巧已经在使用一个视图,因此我只是在该视图中添加了代表星期,月份和年份的额外列,以便通过EF Core轻松分组。

OrderDateDt,
DATEPART(week, OrderDateDt) OrderDateDt_Week,
DATEPART(month, OrderDateDt) OrderDateDt_Month,
DATEPART(year, OrderDateDt) OrderDateDt_Year,