これをCode FirstとDatabase First EFの間の問題に絞りましたが、修正方法がわかりません。できる限り明確にしようとしますが、正直なところ、ここで自分自身の理解の一部を逃しています。これはEntity Framework 4.4です
Entity Frameworkを使用したプロジェクトを継承しましたが、実際のファイルの多くは削除され、実際に戻る方法はありませんでした。 EF(データベースを最初に)を再度追加し、プロジェクトが構築されたT4セットアップを複製しました。すべてのデータベースモデルのコードバージョンとDBContextコードファイルを生成しました。
接続文字列が「通常の」.NET接続文字列のように見える場合、無効な列名「ProcessState_ID」が存在しないというエラーが表示されます。 ProcessState_IDはコードベースにはまったくありません。EDMXファイルなどにはありません。これは、クエリ内の一部の自動EF変換のようです。
接続文字列をEntity Frameworkモデルと一致させると、正常に機能します。
ここで、以前のコードをEntity Frameworkに一致させようとして、「通常の」.NET接続文字列を保持したいと思います。
したがって、ここで2つの質問があります。1.コードで通常の接続文字列からEF接続文字列に移動する良い方法は何ですか? 2.ここに、無効な列名エラーを停止するように見えない別の修正がありますか?
ICollectionがあるかどうかを確認します。
私が理解したのは、テーブルを参照するICollectionがあり、それを把握できる列がない場合、テーブル間を接続しようとする列が作成されることです。これは特にICollectionで発生し、それを理解しようとして「バティー」に追い込まれました。
これは、他の2つの答えをすぐに理解しなかった人(私のような人)にとっては遅刻です。
そう...
EFは、親テーブルのキー参照から期待される名前にマップしようとしています...以来、外部キー名は、データベースの子テーブル関係で「変更または短縮」されました...上記のメッセージが表示されます。
(この修正はEFのバージョンによって異なる場合があります)
私にとっては修正があった:
「ForeignKey」属性をモデルに追加する
public partial class Tour
{
public Guid Id { get; set; }
public Guid CategoryId { get; set; }
[Required]
[StringLength(200)]
public string Name { get; set; }
[StringLength(500)]
public string Description { get; set; }
[StringLength(50)]
public string ShortName { get; set; }
[StringLength(500)]
public string TourUrl { get; set; }
[StringLength(500)]
public string ThumbnailUrl { get; set; }
public bool IsActive { get; set; }
[Required]
[StringLength(720)]
public string UpdatedBy { get; set; }
[ForeignKey("CategoryId")]
public virtual TourCategory TourCategory { get; set; }
}
聖なる牛-何時間も試した後、私はついにこれを理解しました。
私は最初にEF6データベースを実行していますが、「extent unknown column」エラーについて疑問に思っていました-何らかの理由でテーブル名アンダースコア列名を生成し、存在しない列を見つけようとしました。
私の場合、私のテーブルの1つに、別のテーブルの同じ主キーへの2つの外部キー参照がありました。次のようなものです。
Animals Owners
======= ======
AnimalID (PK) Pet1ID <- FK to AnimalID
Pet2ID <- also FK to AnimalID
EFはOwners_AnimalID1
やOwners_AnimalID2
のような奇妙な列名を生成していましたが、その後、壊れてしまいました。
ここでのコツは、これらの紛らわしい外部キーをFluent APIを使用してEFに登録する必要があることです!
メインデータベースコンテキストで、OnModelCreating
メソッドをオーバーライドし、エンティティ構成を変更します。 EntityConfiguration
クラスを拡張する別のファイルを用意することをお勧めしますが、インラインで実行できます。
いずれにしても、次のようなものを追加する必要があります。
public class OwnerConfiguration : EntityTypeConfiguration<Owner>
{
public OwnerConfiguration()
{
HasRequired(x => x.Animals)
.WithMany(x => x.Owners) // Or, just .WithMany()
.HasForeignKey(x => x.Pet1ID);
}
}
そして、それにより、EFは(おそらく)期待どおりに動作し始めます。ブーム。
また、null許容列で上記を使用すると、同じエラーが発生します-.HasOptional()
の代わりに.HasRequired()
を使用してください。
ここに私をハンプにかけるリンクがあります:
そして、Fluent APIドキュメント、特に外部キーの例が役立ちます。
http://msdn.Microsoft.com/en-us/data/jj591620.aspx
ここで説明するように、キーのもう一方の端に構成を配置することもできます。
私が今直面しているいくつかの新しい問題がありますが、それは欠落していた大きな概念上のギャップでした。それが役に立てば幸い!
仮定:
Table
OtherTable
OtherTable_ID
次のいずれかの方法を選択します。
ICollection<Table>
を削除
Table
を取得するときにOtherTable_ID
に関連するエラーが発生した場合は、OtherTable
モデルに移動して、そこにICollection<Table>
がないことを確認してください。関係が定義されていない場合、フレームワークは、OtherTableに対するFKが必要であると自動的に想定し、生成されたSQLでこれらの追加のプロパティを作成します。
この回答のクレジットはすべて@LUKEに属します。上記の回答は、@ drewid回答の下の彼のコメントです。彼のコメントはとてもきれいだと思うので、答えとして書き直しました。
OtherTableId
をTable
に追加そして
OtherTableId
でTable
を定義私の場合、次のような2つの外部キーで構成される主キーを誤って定義していました。
HasKey(x => x.FooId);
HasKey(x => x.BarId);
HasRequired(x => x.Foo)
.WithMany(y => y.Foos);
HasRequired(x => x.Bar);
私が得ていたエラーは、「無効な列名Bar_ID」でした。
複合主キーを指定すると、問題は正しく修正されました。
HasKey(x => new { x.FooId, x.BarId });
...
私にとっての問題は、アプリでテーブルを2回マップしたことです-1回はCode First、もう1回はDatabase Firstです。
いずれかを削除すると、私の場合の問題は解決します。
私にとって、この動作の原因は、Fluent APIで定義されたマッピングの問題が原因でした。関連する2つのタイプがあり、タイプAにはオプションのタイプBオブジェクトがあり、タイプBには多くのAオブジェクトがありました。
public class A
{
…
public int? BId {get; set;}
public B NavigationToBProperty {get; set;}
}
public class B
{
…
public List<A> ListOfAProperty {get; set;}
}
私はこのような流れるようなAPIでマッピングを定義しました:
A.HasOptional(p=> p.NavigationToBProperty).WithMany().HasForeignKey(key => key.BId);
しかし、問題は、タイプBにナビゲーションプロパティList<A>
があったため、結果としてSQLException Invalid column name A_Id
があったことです。
Visual StudioのデバッグをEF DatabaseContext.Database.Logに添付して、生成されたSQLをVS Output-> Debugウィンドウに出力しました
db.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
生成されたSQLには、Bテーブルから2つのリレーションがありました-> 1つは正しいIDで、もう1つはA_Id
問題の問題は、このB.List<A>
ナビゲーションプロパティをマッピングに追加しなかったことです。
だからこれは私の場合、正しいマッピングがどのようになければならなかったかです:
A.HasOptional(p=> p.NavigationToBProperty).WithMany(x => x.ListOfAProperty).HasForeignKey(key => key.BId);
私もこの問題を抱えていましたが、いくつかの異なる原因があるようです。私にとっては、ナビゲーションオブジェクトを含む親クラスで、idプロパティがlongではなくintとして誤って定義されていました。データベースのidフィールドは、C#のlongに対応するbigintとして定義されました。これによりコンパイル時エラーは発生しませんでしたが、OPが取得したのと同じ実行時エラーが発生しました。
// Domain model parent object
public class WidgetConfig
{
public WidgetConfig(long id, int stateId, long? widgetId)
{
Id = id;
StateId = stateId;
WidgetId = widgetId;
}
private WidgetConfig()
{
}
public long Id { get; set; }
public int StateId { get; set; }
// Ensure this type is correct
public long? WidgetId { get; set; }
public virtual Widget Widget { get; set; }
}
// Domain model object
public class Widget
{
public Widget(long id, string name, string description)
{
Id = id;
Name = name;
Description = description;
}
private Widget()
{
}
public long Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
// EF mapping
public class WidgetConfigMap : EntityTypeConfiguration<WidgetConfig>
{
public WidgetConfigMap()
{
HasKey(x => x.Id);
ToTable(nameof(WidgetConfig));
Property(x => x.Id).HasColumnName(nameof(WidgetConfig.Id)).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).IsRequired();
Property(x => x.StateId).HasColumnName(nameof(WidgetConfig.StateId));
Property(x => x.WidgetId).HasColumnName(nameof(WidgetConfig.WidgetId));
}
}
// Service
public class WidgetsService : ServiceBase, IWidgetsService
{
private IWidgetsRepository _repository;
public WidgetsService(IWidgetsRepository repository)
{
_repository = repository;
}
public List<WidgetConfig> ListWithDetails()
{
var list = _repository.ListWithDetails();
return new WidgetConfigMapping().ConvertModelListToDtoList(list).ToList();
}
}
// Repository
public class WidgetsRepository: BaseRepository<WidgetConfig, long>, IWidgetsRepository
{
public WidgetsRepository(Context context)
: base(context, id => widget => widget.Id == id)
{
}
public IEnumerable<WidgetConfig> ListWithDetails()
{
var widgets = Query
.Include(x => x.State)
.Include(x => x.Widget);
return widgets;
}
}
私の場合、この問題の原因は、移行されたデータベースに存在しないFOREIGN KEY制約でした。そのため、既存の仮想ICollectionは正常にロードされませんでした。
同じテーブルへの外部キー参照が複数回ある場合は、InversePropertyを使用できます
このようなもの-
[InverseProperty("MyID1")]
public virtual ICollection<MyTable> set1 { get; set; }
[InverseProperty("MyID2")]
public virtual ICollection<MyTable> set2 { get; set; }
私の場合、シードメソッドデータは、以前の移行で削除されたテーブル列をまだ呼び出していました。 Automapperを使用している場合は、マッピングを再確認してください。
私にとって(Visual Studio 2017とEntity Framework 6.1.3のデータベース優先モデルを使用)、Visual Studioを再起動して再構築すると問題はなくなりました。