Скомпилированный запрос не выполняется - запрос был скомпилирован для источника сопоставления, отличного от того, который связан с указанным DataContext - PullRequest
0 голосов
/ 09 декабря 2018

У меня есть следующий код для скомпилированного запроса Linq2sql для подсчета строк в таблице.Запрос генерирует исключение, несмотря на то, что тот же некомпилированный запрос выполняется гладко:

public static Func<ServiceCustomContext, int> CompiledCount
    = CompiledQuery.Compile((ServiceCustomContext db) => db.Current.Count());
public static int Count()
{
    using (ServiceCustomContext db = new ServiceCustomContext(Constants.NewSqlConnection))
        return CompiledCount(db);
}

ServiceCustomContext наследуется от DataContext и имеет только (кроме конструктора) Table s, включая таблицу с именем Current usedв приведенном выше примере.

И я получаю следующее исключение:

'Запрос был скомпилирован для источника сопоставления, отличного от того, который связан с указанным DataContext.'

Это только при использовании, как указано выше, скомпилированного запроса.Пока у меня есть простое:

return db.Current.Count();

в методе Count(), все в порядке.

Я не понимаю, в чем дело.Я подумал, что, возможно, мне нужно сохранить ссылку на DataContext (ServiceCustomContext), хотя это кажется нелогичным, но даже примеры Microsoft этого не делают.Единственное объяснение, которое я нашел, это здесь , которое в основном состоит в том, что скомпилированные запросы, как упомянуто в примерах Microsoft в ссылке выше, действительно неверны.Я сомневаюсь, что это правда.

1 Ответ

0 голосов
/ 21 декабря 2018

Код будет работать нормально, если только вы используете Count() только один раз за время существования вашего приложения.И ошибка означает именно то, что говорится.Если вы посмотрите на код CompiledQuery:

    private object ExecuteQuery(DataContext context, object[] args) {
        if (context == null) {
            throw Error.ArgumentNull("context");
        }
        if (this.compiled == null) {
            lock (this) {
                if (this.compiled == null) {
                    this.compiled = context.Provider.Compile(this.query);
                    this.mappingSource = context.Mapping.MappingSource;
                }
            }
        }
        else {
            if (context.Mapping.MappingSource != this.mappingSource)
                throw Error.QueryWasCompiledForDifferentMappingSource();
        }
        return this.compiled.Execute(context.Provider, args).ReturnValue;
    }

Вы можете увидеть, что он делает, он фактически компилирует запрос только при первом вызове.Он также сохраняет ссылку на ваш DataContext.Mapping.MappingSource и гарантирует, что вы используете один и тот же MappingSource для каждого последующего вызова.

По умолчанию каждый раз, когда вы создаете новый DataContext, новый MappingSourceсоздан вместе.Это делается в конструкторе, и позже невозможно переопределить его, поскольку свойства DataContext.Mapping и MetaModel.MappingSource имеют только открытый метод получения.Однако существует перегрузка конструктора DataContext, которая принимает MappingSource в качестве аргумента, который (удачи вам) позволяет вам повторно использовать один источник сопоставления в течение всего жизненного цикла вашего приложения.

Не уверен, чтоточные конструкторы вашего ServiceCustomContext класса, но следующий код должен дать вам подсказку решения, чтобы предотвратить возникновение ошибки:

public class ServiceCustomContext : DataContext
{
    private static readonly MappingSource mappingSource = new AttributeMappingSource();

    public ServiceCustomContext(string connection) : base(connection, mappingSource)
    {
    }
}

Я предполагал, что вы используете атрибуты для объявления отображения, однако выможно использовать XmlMappingSource в случае, если вы используете XML-файл для сопоставления вашей базы данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...