У меня есть приложение, написанное с использованием C#
поверх платформы ASP.NET MVC 5.Кроме того, я использую 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
в метод многократного использования, который можно использовать в LINQдо вызова AsEnumerable()
?
ОБНОВЛЕНО
Я также пытался извлечь логику в лямбда-выражение, добавив следующий код в MyModel
class
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;
}
}
тысCommon crawl ru Я пытался использовать его следующим образом:
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