ASP.NET MVC 5(.NET Framework 4.7.2)で「モデルやコントローラーでは参照できるのに、Razor ビュー(.cshtml)だけ System.Data.Objects が解決できずビルドに失敗する」――現場で頻出する躓きです。本稿は原因を原理から整理し、Web.config の最小変更で即座に解決する手順、周辺知識、落とし穴、そして長期的な移行戦略までを一気通貫で解説します。
現象の整理:ビューだけ System.Data.Objects が見つからない
以下のように、モデルやコントローラーではコンパイル可能なのに、ビュー内で @using System.Data.Objects を書くとコンパイル エラー(CS0246 等)になるケースがあります。
// Controller/Model 側(問題なし)
using System.Data.Objects;
public class HomeController : Controller {
public ActionResult Index() {
// ここではコンパイルOK
return View();
}
}
// View 側(.cshtml 内):エラー
@using System.Data.Objects
@{
// "The type or namespace name 'Objects' could not be found" 等
}
これは「Razor ビューのコンパイル」が、プロジェクト(C#)コンパイルとは別経路で行われ、Razor コンパイラに参照アセンブリを個別登録しないと名前空間解決が行われないためです。
原因の核心:Razor は独立してアセンブリ参照を解決する
ASP.NET MVC の Razor ビューは、実行時(または発行時の事前コンパイル)に ビューごとにコンパイルされます。Razor は次の情報から参照を決定します。
- Web.config の
<system.web><compilation><assemblies>に登録されたアセンブリ - (Razor 固有)
<system.web.webPages.razor><pages><namespaces>に登録された既定のusing
従って、プロジェクト参照で System.Data.Entity.dll(System.Data.Objects を内包)を参照していても、Web.config 側にアセンブリ登録が無い限り、ビューでは解決されないのです。
最短の解決策:Web.config に System.Data.Entity を追加
アプリのルート(推奨)または /Views 直下の Web.config に、次の 1 行を追加します。これで Razor からも System.Data.Objects が参照可能になります。
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.7.2">
<assemblies>
<!-- 追加する行 -->
<add assembly="System.Data.Entity, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089" />
</assemblies>
</compilation>
</system.web>
</configuration>
加えて、頻繁に使う場合は <namespaces> に名前空間を登録しておくと各ビューで @using が不要になります。
<system.web.webPages.razor>
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="System.Data.Objects" />
<!-- 既定の MVC 名前空間群... -->
</namespaces>
</pages>
</system.web.webPages.razor>
この 2 点で「ビューだけ解決できない」問題は解消します。
どこに書くべき? ルート vs Views 直下
基本方針は「ルートの Web.config に書く」です。理由は以下の通りです。
- アプリ全体で一貫した参照設定となり、ビュー以外のランタイム機構(WebForms ビルドプロバイダ等)にも影響を及ぼせる
- Config の分散を避け、運用時の見落としを減らせる
ただし、複数アプリケーションを同一 IIS サイト配下で動かす等の事情で、/Views フォルダーだけの局所設定にしたい場合は /Views/Web.config でも構いません。
典型エラーメッセージと対処対応表
| エラーメッセージ(例) | 想定原因 | 対処 |
|---|---|---|
| CS0246: The type or namespace name ‘Objects’ could not be found | Razor 参照不足(System.Data.Entity 未登録) | ルート Web.config の <assemblies> に追加 |
| Parser Error: Could not load file or assembly ‘System.Data.Entity…’ | サーバーに DLL が無い/バインディング不一致 | 対象サーバーに .NET Framework を適用・再配布、もしくは bin 配置を検討 |
| CS0104: ‘DbSet’ is an ambiguous reference… | EF6 の EntityFramework.dll と BCL の型が衝突 | 完全修飾名で明示、または不要参照を除去・移行 |
なぜ System.Data.Objects なのか:歴史的背景
System.Data.Objects は、.NET Framework の System.Data.Entity.dll に含まれる古い Entity Framework(EF 4.x/5 世代)の API 群(ObjectContext、ObjectQuery<T> など)です。EF6 では多くの型が System.Data.Entity.Core.* に移り、EF Core ではさらにアーキテクチャが刷新されました。
- EF 4/5:
System.Data.Objects(BCL, System.Data.Entity.dll) - EF 6:
System.Data.Entity.Core.Objects(NuGet: EntityFramework.dll + 一部 BCL) - EF Core: ObjectContext 系 API 自体が無く、DbContext 中心
新規開発や中長期運用では、可能なら EF6 以降(または EF Core)へ移行する方が保守性は高くなります。本稿の対処は「既存資産を動かす」ためのピンポイント解決と捉えてください。
実務での安全な作業手順(チェックリスト)
- 現状把握: プロジェクトが EF 4/5 を使っているか、EF6/EF Core かを確認。
packages.configや参照設定を見ます。 - バックアップ: ルートと
/Viewsの Web.config をバックアップ。 - 最小変更: ルート Web.config の
<assemblies>にSystem.Data.Entityを 1 行追加。 - 名前空間の既定化:
<system.web.webPages.razor>→<namespaces>にSystem.Data.Objectsを追加(任意)。 - ビルド&実行: 該当ビューがコンパイルされる画面を開き、エラー消失を確認。
- ログ監視: イベントログやアプリログにアセンブリ ロード例外が出ていないか確認。
- 発行設定: 発行(パブリッシュ)プロファイルで「プリコンパイル」有無を確認。プリコンパイル運用でも本設定は有効です。
サンプル:Views から ObjectQuery<T> を参照する
繰り返しになりますが、ビューで直接クエリを実行すること自体は推奨されません。以下はあくまで参照解決の確認用サンプルです。
// Views/Web.config に <add namespace="System.Data.Objects" /> を登録済みと仮定
@{
// ここで型名が解決できれば OK(実際の DB アクセスは Controller/Service で行うべき)
ObjectQuery<string> dummy = null;
}
<p>System.Data.Objects の型が Razor から解決できました。</p>
よくある落とし穴と回避策
アセンブリ バージョンの表記
System.Data.Entity は .NET 4.x 系でアセンブリ バージョン「4.0.0.0」として統一的に扱われます。Web.config の 1 行は そのまま使えば問題ありません(アセンブリ バインディング リダイレクトの影響を受けにくい)。
本番サーバーに DLL が無い
通常は .NET Framework の一部としてサーバーに用意されますが、レガシー環境や最小ロール構成では不足することがあります。Windows の更新適用や .NET 再配布で補完してください。必要に応じて bin 配置(ローカルコピー)で回避する方法もありますが、BCL 系 DLL は基本的に GAC 依存が前提です。
EF6 と混在している
EF6 プロジェクトにおいて、誤って System.Data.Objects と System.Data.Entity.Core.Objects を混在させると曖昧性や実行時不整合が発生します。EF6 では System.Data.Entity.Core.Objects を優先し、必要なら完全修飾名で明示してください。
View にロジックを置きすぎる
ビューは 表示専用 とし、複雑なデータ取得はコントローラーやサービス層で済ませ、ビューモデルへ詰め替えるのが王道です。System.Data.Objects を「参照できる」ことと「使ってよい」ことは別問題です。
ベストプラクティス:長期保守を見据えた設計
- ビューモデル化: クエリ結果を表示用 DTO/ビューモデルに射影し、ビューは
@modelを強く型付け。 - 非同期アクション: データアクセスは非同期化してスレッドプール圧迫を回避(EF6 以降/EF Core で
async/await)。 - EF の世代統一: 同一ソリューションで EF4/5 と EF6/EF Core を混在させない。
- 依存の明示: 参照 DLL はルート Web.config の
<assemblies>に集約し、レポジトリ内の設定差分を小さく保つ。 - 移行計画: 新規開発は可能な限り EF6 もしくは EF Core を前提にし、レガシー層は段階的に置き換える。
設定例:最小セットと拡張セット
最小セット(これだけで動く)
<system.web>
<compilation debug="true" targetFramework="4.7.2">
<assemblies>
<add assembly="System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</assemblies>
</compilation>
</system.web>
拡張セット(名前空間の既定化を含む)
<system.web.webPages.razor>
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="System.Data.Objects" />
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Html" />
</namespaces>
</pages>
</system.web.webPages.razor>
移行の指針:EF6 / EF Core を使う場合
新規/更新開発では次のように書き換えます。
- 名前空間:
System.Data.Entity.Core.Objects(EF6)へ置換 - DbContext への移行:
ObjectContext直使用をやめ、DbContextとDbSetのパターンへ - Razor からの参照: そもそもビューではデータアクセス API を直接参照しない(ViewModel のみ)
移行は一気に行わず、外縁から(ビュー → コントローラー → サービス → リポジトリ)へ段階的に進めると安全です。
ケーススタディ:小規模レガシー MVC5 の延命対応
実務では「まずは止まらない」ことが最優先です。以下は最短で安定化させるチェックリストです。
- ルート Web.config に
System.Data.Entityを追加。 - ビルド・動作確認。
- ビューからの直接参照を段階的に削減(ヘルパー・拡張メソッドや DisplayTemplate への置換)。
- 中規模以上では、サービス層(アプリケーション サービス)を用意し、データ取得はそこに集約。
- CI で ビューのコンパイル検証 を有効化(プリコンパイルや Razor 自動テストで早期検出)。
補足知識:プリコンパイル運用と挙動の違い
発行時に「ビューをプリコンパイル」する設定を有効にしていても、参照解決の情報源は Web.config である点は変わりません。従って、本記事で示した <assemblies> の 1 行はプリコンパイル/ランタイム コンパイルのどちらでも有効です。
テスト観点:壊れにくい設定にするために
- コンフィグの一元化: ルート Web.config に集約し、
/Views/Web.configは名前空間のみに留める。 - スモークテスト: 代表的な画面をカバーする UI テストを 1 本だけでも用意(ビューのコンパイルを通す)。
- ログの可視化: コンパイル例外・アセンブリ ロード例外を捕捉するフィルターを実装。
まとめ:原因は「Razor の参照不足」、解決は「Web.config に 1 行」
ASP.NET MVC のビューで System.Data.Objects が使えない場合、原因はほぼ 100%「Razor の参照が不足している」ためです。ルート(または /Views)の Web.config に System.Data.Entity を 1 行追加し、必要に応じて <namespaces> に System.Data.Objects を登録する――これだけで実務の多くは解決します。
ただし、長期的にはビューモデル化・EF6/EF Core への移行を計画し、ビューからデータアクセス API の直接参照を無くしていくことが保守性と品質を高めます。
付録:コピペ用スニペット集
ルート Web.config(追加差分)
<system.web>
<compilation debug="true" targetFramework="4.7.2">
<assemblies>
<add assembly="System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</assemblies>
</compilation>
</system.web>
Views/Web.config(任意:名前空間の既定化)
<system.web.webPages.razor>
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="System.Data.Objects" />
</namespaces>
</pages>
</system.web.webPages.razor>
EF6 を使う場合の名前空間
using System.Data.Entity.Core.Objects; // EF6 以降
FAQ:現場でよく受ける質問
Q. ルートではなく /Views/Web.config にだけ追加しても良い?
A. 動作上は可能ですが、設定の分散は運用リスクです。原則はルートへ追加し、/Views 側は名前空間の既定化に留めるのが安全です。
Q. なぜプロジェクト参照に追加しているのに、ビューだけ失敗するの?
A. C# コンパイラと Razor コンパイラは参照解決の情報源が異なるからです。Razor は Web.config の <assemblies> を見ます。
Q. 本番でだけ失敗することはある?
A. あります。IIS 上の実行ユーザーや GAC の有無、発行方法の違いでアセンブリ解決に差が出るためです。発行プロファイルと本番の .NET Framework 状態を揃えましょう。
Q. View での DB アクセスは本当にダメ?
A. 小規模であっても、表示ロジックとデータ取得の分離は後の不具合低減に直結します。表示用の整形はヘルパーや Display/EditorTemplate を活用し、データは Controller/Service で完結させるのが理想です。
チェックポイント早見表
| 項目 | 推奨設定 | 備考 |
|---|---|---|
| アセンブリ登録 | ルート Web.config の <assemblies> に System.Data.Entity | Version=4.0.0.0, PKT=b77a5c561934e089 |
| 名前空間の既定 | System.Data.Objects を <namespaces> に追加 | 任意(利便性向上) |
| ビューモデル | 強く型付け(@model) | データ取得は Controller/Service で完了 |
| EF の世代 | 新規は EF6 / EF Core | レガシー維持は本稿の対処で可 |
| テスト | 主要画面のスモークテスト | ビューのコンパイルを通す |
おわりに
Razor ビューのコンパイルは「別ビルド」である――この一点を押さえれば、今回の問題は迷わず解決できます。まずは Web.config に 1 行、そして将来に向けた段階的な改善。レガシーと新技術のバランスを取りながら、安全に保守していきましょう。

コメント