Поделиться через


Entity Framework FAQ: Error Messages (ru-RU)

[[articles:Entity Framework FAQ (ru-RU)|Содержание EF FAQ]]

 

MetadataException: Unable to load the specified metadata resource

Причиной возникновения этой ошибки является неверно оформленная или отсутствующая строка подключения. TВ частности, причиной этой ошибки является неверно заданные параметры метаданных в строке подключения.

Перед тем, как начать устранять неполадки следует убедится, что вы редактируете правильный файл со стройкой подключения.

Строка подключения загружается из конфигурационного файла *запускаемого* приложения, и не факт, что модель Entity Framework описана именно в этой сборке. Например, если у вас есть сборка в которой описана модель Entity Framework и веб приложение, которое использует сборку с моделью данных, тогда строку подключения  Entity Framework следует описать в файле `Web.config` для веб приложения. Сборка содержащая модель данных может иметь свою собственную строку подключения, если вам этого хочется (это удобно, т.к. ее будет использовать дизайнер Entity Framework для обновлений), но во время выполнения она не будет использоваться веб приложением.

В MSDN строки соединения подробно описаны. Но причиной этой ошибки является именно параметр `metadata`. Этот параметр указывает Entity Framework где искать EDMX во время выполнения. Более подробную информацию о структуре этого параметра можно найти в  этой статье.

Unable to create a constant value of type 'SomeType'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.

Вы можете встретить следующую ошибку, когда запускаете запрос LINQ 2 Entities:

System.NotSupportedException
Unable to create a constant value of type 'System.Object'.
Only primitive types ('such as Int32, String, and Guid') are supported in this context.

Это сообщение может сообщать, что вы пытаетесь сделать сравнение экземпляров сущностей вместо их ключей. Это невозможно.

Следующие два запроса работать не будут:

    var first = Context.Foos.First();
    var again = Context.Foos.Where(f => f == first).Single();

...потому что правильно будет написать так:

    var again = Context.Foos.Where(f => f.Id == first.Id).Single();

Запросы LINQ 2 Entities конвертируются в  SQL, который ничего не знает о срванении ссылок на записи в таблице, но сравнение на основе основных ключей будет работать.

Так же эта проблема может возникнуть из-за упаковки (boxing):

    var wrong = Context.Foos.Where(f => f.SomeBoolean.Equals(true)).Single(); // runtime error
    var right = Context.Foos.Where(f => f.SomeBoolean).Single();              // works

В первом случае, значение булевого типа упаковывается вызовом  Equals(Object obj). Во втором случае этого не происходит, и все работает.

Cannot compare elements of type 'MyNamespace.SomeComplexType'. Only primitive types (such as Int32, String, and Guid) and entity types are supported.

LINQ 2 Entities не поддерживает непосредственного сравнения сложных типов  с null’ем. Но типы сущностей, с null’ем вы сравнивать можете.

    var wrong = Context.Foos
                       .Where(f => f.SomeComplexType == null)
                       .Single();                                         // runtime error
    var right = Context.Foos
                       .Where(f => f.SomeComplexType.SomeString == null)
                       .Single();                                        // works
    var works = Context.Foos
                       .Where(f => f.SomeEntity == null)
                       .Single();                                        // works

На самом деле, сложные типы крайне редко бывают полностью обнулены, даже если отложенная загрузка отключена, или даже если значения никогда не присваиваются. Поэтому обычно нет причины сравнивать сложный тип с нулем.

The methods 'Single' and 'SingleOrDefault' can only be used as a final query operation. Consider using the method 'FirstOrDefault' in this instance instead.

В запросах LINQ 2 Entities вы можете использовать как FirstOrDefault() так и SingleOrDefault в качестве последней операции запроса:

    var right = Context.Foos
                       .Where(f => f.SomeBoolean)
                       .FirstOrDefault();                                        // works
    var works = Context.Foos
                       .Where(f => f.SomeBoolean)
                       .SingleOrDefault();                                       // works


Однако внутри запроса вы не можете использовать SingleOrDefault:

    var wrong = Context.Foos
                       .Where(f => f.SomeBoolean)
                       .Select(f => f.Bars.SingleOrDefault())
                       .SingleOrDefault();                                       // Runtime error
    var right = Context.Foos
                       .Where(f => f.SomeBoolean)
                       .Select(f => f.Bars.FirstOrDefault())
                       .SingleOrDefault();                                       // works


Обратите внимание, что последний  SingleOrDefault всегда корректен, но внутренний приходится заменять на FirstOrDefault. Причина кроется в реализации  SingleOrDefault. Приведенный запрос указывает серверу баз данных вернуть первые две строки и выкинуть ошибку, если они отличаются. Запрос LINQ 2 Entities – все, кроме последнего  SingleOrDefault будет преобразовано в SQL, так как такое поведение невозможно выразить чистым SQL запросом.

[[articles:Entity Framework FAQ (ru-RU)|Содержание EF FAQ]]