假设我有一个Magazine类,其enum属性描述了订阅期(Monthly,Bimonthly,Quarterly,...)。因此,选择枚举中的值,可以使一些计算变得容易
使用实体框架我有DbContext
DbSet<Magazine>
enum SubscriptionPeriodType
{
Monthly = 1,
Bimonthly = 2,
Quarterly = 3,
Annual = 12,
};
class Magazine
{
public SubscriptionPeriodType SubscriptionPeriodType {get; set;}
...
}
public MyDbContext : DbContext
{
public DbSet<Magazine> Magazines {get; set;}
...
}
鉴于一年内的日期,我想知道订阅期的第一天和最后一天。例如,如果我有季度订阅期,则为2016年5月15日,即2016年4月1日订阅期的第一天,最后一天为2016年6月30日。
计算如下(按照婴儿步骤)
Period CalculatePeriod(DateTime date)
{
SubscriptionPeriodType subscriptionPeriodType = dbContext.Magazines
.Where(...)
.Select(magazine => magazine.SubscriptionPeriodType;
int periodLength = (int)subscriptionPeriodType;
int periodNr = (date.Month - 1) / periodLength;
// quarters are numbered 0..3
int periodStartMonth = periodNr * periodLength + 1;
// quarters start in months 1 / 4 / 7 / 10
DateTime startPeriod = new DateTime(date.Year, periodStartMonth, 1);
DateTime nextPeriod = startPeriod.AddMonths(periodLength);
return new Period()
{
FirstDay = startPeriod,
LastDay = nextPeriod.AddDays(-1),
}
虽然此功能可以在IEnumerable.Select
中使用,但却无法在IQueryable.Select
中使用。您无法在IQueryable.Select
中创建阻止声明。
但是,到达StartPeriod
和NextPeriod
的计算非常简单。我想创建一个表达式树,我可以将其提供给我的Select语句。
到目前为止我做了什么 我知道如何将前几个语句创建为表达式:
Expression<Func<Magazine, SupbscriptionPeriodType>> e1 =
magazine => magazine.SubscriptionPeriodType;
Expression<Func<SubscriptionPeriodType, int>> PeriodLength = s => (int)s;
Expression<Func<DateTime, int, int>> PeriodNr =
(date, periodLength) => (date.Month - 1) / periodLength;
// etc.
但是如何将这些表达式连接成一个表达式以及如何在Select?
中调用它var result = dbContext.Magazines
.Where(...)
.Select(magazine => ConcatenatedExpression.... )