我在ASP.NET MVC 5框架的顶部有一个使用C#
编写的应用程序。另外,我正在使用EntityFramework 6.2作为ORM与我的数据进行交互。
我使用Fluent LINQ编写了以下join语句
List<string> names = new List<string>{"", ....};
query = TopLevelQuery.Where(x => x.EndedAt.HasValue && x.StartedAt >= startedAt && x.EndedAt.Value <= endedAt)
.Join(UserService.QueryUniqueRecords(),
entry => entry.UserId,
rec => rec.UserId,
(entry, rec) => new { entry, rec })
.Where(result => result.entry.IsEqualDateOf(result.rec.DayOf)
&& names.Contains(result.rec.Name))
.Select(x => x.entry);
但是,在运行时出现以下错误
LINQ to Entities无法识别方法'IsEqualDateOf',并且 此方法不能转换为商店表达式。
这是我的IsEqualDateOf
扩展方法
public static class MyModelExtensions
{
public static DateTime GetLocalDate(this MyModel entry)
{
var local = DbFunctions.TruncateTime(SqlFunctions.DateAdd("ss", entry.UtcOffset, entry.StartedAt));
return local.Value;
}
public static bool IsEqualDateOf(this MyModel entry, DateTime dateOf)
{
bool isEqual = entry.GetLocalDate().Equals(dateOf.Date);
return isEqual;
}
}
但是,如果我将LINQ表达式转换为以下伪表达式,它将按预期工作
query = TopLevelQuery.Where(x => x.EndedAt.HasValue && x.StartedAt >= startedAt && x.EndedAt.Value <= endedAt)
.Join(UserService.QueryUniqueRecords(),
entry => entry.UserId,
rec => rec.UserId,
(entry, rec) => new { entry, rec })
.Where(result => DbFunctions.TruncateTime(SqlFunctions.DateAdd("ss", entry.UtcOffset, entry.StartedAt)) == result.rec.DayOf
&& names.Contains(result.rec.Name))
.Select(x => x.entry);
但是,我希望能够在项目中的多个地方重用相同的逻辑,这就是为什么我想将其提取到某种扩展或方法中的原因。
如何将DbFunctions
和SqlFunctions
调用提取到可重用的方法中,在调用AsEnumerable()
之前可在LINQ中使用该方法?
已更新
我还尝试通过向MyModel
类添加以下代码来将逻辑提取到lambda表达式中
public class MyModel
{
public DateTime StartedAt { get; set; }
public int UtcOffset { get; set; }
// ...
public Expression<Func<MyModel, bool>> IsDateOf(DateTime dayOf)
{
return p => p.StartedAt.AddSeconds(p.UtcOffset) == dayOf.Date;
}
}
然后我尝试像这样食用它
query = TopLevelQuery.Where(x => x.EndedAt.HasValue && x.StartedAt >= startedAt && x.EndedAt.Value <= endedAt)
.Join(UserService.QueryUniqueRecords(),
entry => entry.UserId,
rec => rec.UserId,
(entry, rec) => new { entry, rec })
.Where(result => result.entry.IsDateOf(result.rec.DayOf)
&& names.Contains(result.rec.Name))
.Select(x => x.entry);
但是在尝试使用它时会引发以下语法错误
运算符'&&'不能应用于类型的操作数 '
Expression<Func<MyModel,bool>>
'和bool。
此外,我尝试将IsDateOf
表达式设为静态,并这样称呼它
query = TopLevelQuery.Where(x => x.EndedAt.HasValue && x.StartedAt >= startedAt && x.EndedAt.Value <= endedAt)
.Join(UserService.QueryUniqueRecords(),
entry => entry.UserId,
rec => rec.UserId,
(entry, rec) => new { entry, rec })
.Where(result => result.entry.Where(MyModel.IsDateOf(result.rec.DayOf))
&& names.Contains(result.rec.Name))
.Select(x => x.entry);
但这给了我以下语法错误
“ MyMode”不包含
Where
和最佳定义 扩展方法重载Queryable.Where<MyModel>IQueryable<MyModel>, Expression<Func<MyModel, bool>>)
需要一个IQueryable类型的接收者
答案 0 :(得分:2)
从方法中删除参数,并使表达式接受两个参数:
public static Expression<Func<MyModel, DateTime, bool>> IsDateOf
= (MyModel p, DateTime d) => p.StartedAt.AddSeconds(p.UtcOffset) == d.Date;
请注意,我将其设置为静态字段,而不是方法。然后在LINQ表达式中,您需要调用它:
MyModel.IsDateOf(result.entry, result.rec.DayOf)
如果不将其设为字段(或属性),则必须首先调用该方法以获取表达式;那么您需要调用表达式:
MyModel.IsDateOf()(result.entry, result.rec.DayOf)
在我看来,这看起来很奇怪。