Avatar ·

Ошибка MetadataException: Unable to load the specified metadata resource в Entity Framework

Всем привет! Я новичок в C# и Entity Framework. Создал модель базы данных с помощью подхода Database First (сгенерировал .edmx из существующей БД). Всё компилируется без ошибок, но при попытке выполнить любой запрос к контексту данных вылетает исключение: ``` System.Data.MetadataException: Unable to load the specified metadata resource. ``` Вот мой код контекста (упрощённо): ```csharp public partial class MyEntities : DbContext { public MyEntities() : base("name=MyEntities") { } } // Использование: using (var db = new MyEntities()) { var users = db.Users.ToList(); // Здесь вылетает ошибка } ``` Строка подключения в App.config: ```xml ``` Вроде бы всё стандартно, но ошибка появляется. Я проверил, что файл .edmx существует в проекте, и модель называется MyModel. Что я делаю не так? Как правильно указать путь к метаданным? Заранее спасибо за помощь! <<>>

Причина ошибки

Ошибка MetadataException возникает, когда Entity Framework не может найти файлы метаданных (.csdl, .ssdl, .msl) по указанному пути в строке подключения. Чаще всего это происходит из-за неправильного формата ресурса res://*/ или из-за того, что файлы .edmx не включены в сборку как встроенные ресурсы (Embedded Resource).

Решение: правильный формат строки подключения

В подходе Database First файлы метаданных хранятся внутри сборки как встроенные ресурсы. Строка подключения должна указывать на них в формате:

metadata=res://*/MyModel.csdl|res://*/MyModel.ssdl|res://*/MyModel.msl

Но здесь есть нюанс: символ * означает «любая сборка в домене приложения». Если ваша модель находится в другой сборке (например, в отдельной библиотеке классов), нужно указать полное имя сборки вместо звёздочки. Однако чаще проблема в другом — файлы .edmx генерируются с неправильным именем ресурса.

Как проверить и исправить

  1. Убедитесь, что файлы .edmx компилируются как встроенный ресурс: щёлкните правой кнопкой по файлу .edmx в Solution Explorer → Properties → Build Action = "Embedded Resource".
  2. Проверьте реальное имя ресурса: откройте .edmx файл в текстовом редакторе (например, Notepad++). В начале файла вы увидите что-то вроде:
    <edmx:Edmx xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx" Version="2.0">
      <edmx:Runtime>
        <edmx:ConceptualModels>
          <Schema Namespace="MyModel" ...>
    Обратите внимание на атрибут Namespace — это часть имени ресурса. Фактическое имя ресурса будет: YourAssemblyName.MyModel.csdl (и аналогично для .ssdl и .msl).
  3. Исправьте строку подключения: вместо res://*/ используйте полный путь к сборке. Например, если ваша сборка называется MyApp.exe или MyLibrary.dll, напишите:
    metadata=res://MyApp/MyModel.csdl|res://MyApp/MyModel.ssdl|res://MyApp/MyModel.msl
    Или, чтобы быть уверенным на 100%, используйте полное имя сборки (включая версию и культуру):
    metadata=res://MyApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null/MyModel.csdl|...
  4. Альтернативный простой способ: замените res://*/ на res://YourAssemblyName/. Например, если ваша сборка называется DataLayer, то строка будет:
    metadata=res://DataLayer/MyModel.csdl|res://DataLayer/MyModel.ssdl|res://DataLayer/MyModel.msl

Проверка с помощью утилиты

Вы можете использовать встроенную утилиту EdmGen.exe (из папки SDK) для просмотра всех ресурсов в сборке:

EdmGen.exe /ViewGenSchemas "YourAssembly.dll"

Она покажет точные имена ресурсов, которые нужно указать в строке подключения.

Итоговый рабочий пример

Если ваша сборка называется MyApp.exe, строка подключения должна выглядеть так:

<connectionStrings>
    <add name="MyEntities" 
         connectionString="metadata=res://MyApp/MyModel.csdl|res://MyApp/MyModel.ssdl|res://MyApp/MyModel.msl;
                           provider=System.Data.SqlClient;
                           provider connection string='data source=localhost;initial catalog=MyDB;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework'"
         providerName="System.Data.EntityClient" />
</connectionStrings>

После этого пересоберите проект и запустите — ошибка должна исчезнуть.

<<>>

Альтернативное решение: использование Code First вместо Database First

Если вы не хотите возиться с метаданными и строками подключения, рассмотрите переход на Code First подход. В этом случае вы сами пишете классы сущностей и контекст, а Entity Framework сам создаёт БД (или маппится на существующую).

Пример:

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class MyContext : DbContext
{
    public DbSet<User> Users { get; set; }
    
    public MyContext() : base("name=MyConnectionString") { }
}

В строке подключения уже не нужно указывать метаданные — просто обычная строка для SQL Server:

<add name="MyConnectionString" 
     connectionString="data source=localhost;initial catalog=MyDB;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework"
     providerName="System.Data.SqlClient" />

Этот подход проще, не требует .edmx файлов и решает проблему с MetadataException раз и навсегда. Если у вас уже есть БД, используйте Entity Framework Power Tools для генерации классов Code First из существующей схемы.

Недостаток: вы теряете визуальный редактор модели, но для небольших проектов это не критично.