#c# #linq-to-sql
#c# #linq-to-sql
Вопрос:
Я столкнулся со странной проблемой при использовании CompiledQuery.Compile
. При попытке использовать статическое поле только для чтения в запросе я получаю следующее сообщение об ошибке:
Class member X is unmapped
Если я перенесу определение поля из частичного класса в другой класс, не связанный с LINQ-SQL, я получу следующее:
Object reference not set to an instance of an object
Если я передаю поля в качестве аргумента, я не вижу ошибок, и запрос работает нормально и генерирует ожидаемый SQL.
Пример приведен ниже:
partial class Order
{
public static readonly string Complete = "Complete";
public static readonly string Pending = "Pending";
public static readonly Func<DataContext, Order, bool> IsComplete =
CompiledQuery.Compile((DataContext context, Order o) =>
Complete == o.Status);
}
Использование:
var test = from o in db.Orders
select new
{
IsComplete = Order.IsComplete(db, o)
};
Это приводит к упомянутым ошибкам. Если я добавлю a string[]
в качестве другого аргумента CompiledQuery
, то я не вижу ошибок. Кроме того, если я изменю строки, чтобы они были const
вместо static readonly
этого, это также работает, но я полагаю, что это связано со значениями, присваиваемыми во время компиляции.
Есть ли какой-нибудь способ заставить static readonly
поля работать?
Комментарии:
1. Вы пробовали использовать
public static readonly Func<DataContext, Order, bool> IsComplete = CompiledQuery.Compile((DataContext context, Order o) => Order.Complete == o.Status);
2. Просто попробовал это, это дает:
Class member Order.X is unmapped
.3. Может быть, попробуйте вместо этого превратить все три поля в средства доступа?
public static string Complete { get { return "Complete"; } }
Дает ли это тот же результат?4. Должно ли это быть поле, может ли оно быть константой
public const string Complete="Complete"
5. Тот же результат, когда в
Order
частичном классе и другом классе.
Ответ №1:
Проблема возникает из-за того, что Linq-To-Sql пытается преобразовать ваше выражение в серверный SQL, поскольку логика видит не сопоставленный член класса и не может справиться с его преобразованием.
Я бы посоветовал вам создать свойство переноса, которое выполнит всю работу за вас
partial class Order {
public static readonly string Complete = "Complete";
public static readonly string Pending = "Pending";
private static readonly Func<DataContext, Order, bool> _isComplete;
public static Func<DataContext, Order, bool> IsComplete {
get {
if (_isComplete == null) {
var complete=Complete;
_isComplete CompiledQuery.Compile((DataContext context, Order o) =>
complete == o.Status);
}
return _isComplete;
}
}
}
}
Комментарии:
1. Не совсем уверен, почему это работает, но это так. Кроме того, свойства только для чтения не разрешены в
Func
. Приветствия.2. Я удалил только для чтения из вызова свойства (вызвано слишком большим количеством копирования и вставки). Причина, по которой это работает, заключается в том, что вы в конечном итоге передаете локальную переменную в скомпилированный лямбда-код вместо фактического свойства. Это позволяет LinqToSql правильно оценить его.
Ответ №2:
Нет проблем, если вы не смешиваете обычные запросы и скомпилированные запросы. Следующее работает и даст вам лучшую производительность в целом, за счет невозможности повторного использования простого IsCompleted
скомпилированного везде, где вам нравится.
public static readonly Func<YourDataContext, IEnumerable<Order>> GetCompletedOrders =
CompiledQuery.Compile((YourDataContext context) =>
context.Orders.Where(o => Complete == o.Status));