LINQ-SQL — использование статических полей только для чтения в CompiledQuery.Скомпилировать?

#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));