【发布时间】:2018-12-26 20:31:46
【问题描述】:
我在 ASP.NET MVC 5 框架的顶部使用C# 编写了一个应用程序。此外,我使用 EntityFramework 6.2 作为 ORM 来与我的数据进行交互。
我使用 Fluent LINQ 编写了以下连接语句
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>>' 和布尔值。
此外,我尝试将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 类型的接收器
【问题讨论】:
-
AFAIK 你必须把它变成一个 lambda 表达式而不是一个方法,比如
Expression<Func<Datetime, bool>>,它不能有一个主体。有关我的意思的示例,请参见 this question。 -
@Amy 我实际上已经尝试过了。请检查我更新的问题。
-
您正在调用一个返回表达式的方法。您没有调用表达式。
-
你现在为什么要打电话给
result.entry.Where?摆脱它。 -
由于某种原因,您现在拥有
.Where(result => result.entry.Where(MyModel.IsDateOf(result.rec.DayOf)) && names.Contains(result.rec.Name))将其更改为.Where(result => MyModel.IsDateOf(result.entry, result.rec.DayOf) && names.Contains(result.rec.Name))
标签: c# asp.net-mvc entity-framework linq entity-framework-6