データ アクセスに Entity Framework 5 (生成された POCO を使用したデータベース ファースト) を使用して MVC4 Web アプリケーションを作成しています。
アプリでは、ユーザーはいくつかの画面を通過し、ドキュメントを作成または編集します (「ケース スタディ」と呼ばれます)。最終画面に到達すると、ドキュメントは CaseStudy POCO としてメモリに存在し、この構造をデータベースに保存するまではすべて問題ありません。
ドキュメントを保存するために、いくつかのデータベース テーブルを定義しました。これらのテーブルは、ビジネス レイヤーで使用される EF POCO にマップされ、MVC コントローラーによって使用されます。そのため、有効期間が短い DbContext を使用して POCO を取得し、リクエスト間のセッションに保存します。
その結果、保存画面では、ナビゲーション プロパティを持つこの POCO のコンテンツを既存のテーブル データ (Category、Layout、および Sections テーブル) に保存し、追加または更新されたデータ (CaseStudySections および CaseStudy 自体) も保存する必要があります。したがって、すべての POCO は新しいものであるか、それらを取得するために使用されたコンテキストが長い間破棄されています。言い換えれば、それらはすべて「分離」されています。
この投稿で珍しいのは、私がすでに実用的な解決策を手にしていることです。問題は、かさばり、もろく、洗練されていないことです。以下にコードを掲載しています。サブコレクションの繰り返し、明示的な追加と添付、エントリ オブジェクトを取得して個々のプロパティを変更済みとしてマークする必要があること、および最後に追加のマテリアル コレクションを同期させるためのひどい歌とダンスに注意してください。これが EF5 で切り離された POCO を処理するために必要なものである場合、私はがっかりします。
ここで何か不足していますか?これはベストプラクティスと一致していますか? POCO の構造をアタッチして挿入/更新する、より適切で簡潔な方法はありますか?
ケーススタディを保存するコード:
public void SaveCaseStudy(CaseStudy caseStudy)
{
foreach (var s in caseStudy.CaseStudySections)
{
this.Entities.Sections.Attach(s.Section);
if (s.CreatedByRefId == default(Guid))
{
s.CreatedByRefId = this.UserRefId;
s.CreatedTime = DateTime.Now;
this.Entities.CaseStudySections.Add(s);
}
else
{
this.Entities.CaseStudySections.Attach(s);
var entry = this.Entities.Entry(s);
entry.Property(e => e.TextData).IsModified = true;
entry.Property(e => e.BinaryData).IsModified = true;
}
s.LastModifiedByRefId = this.UserRefId;
s.LastModifiedTime = DateTime.Now;
}
foreach (var m in caseStudy.AdditionalMaterials)
{
if (m.CreatedByRefId == default(Guid))
{
m.CreatedByRefId = this.UserRefId;
m.CreatedTime = DateTime.Now;
this.Entities.AdditionalMaterials.Add(m);
}
else
{
this.Entities.AdditionalMaterials.Attach(m);
}
m.LastModifiedByRefId = this.UserRefId;
m.LastModifiedByTime = DateTime.Now;
}
this.Entities.Layouts.Attach(caseStudy.Layout);
this.Entities.Categories.Attach(caseStudy.Category);
if (caseStudy.CreatedByRefId != default(Guid))
{
this.Entities.CaseStudies.Attach(caseStudy);
var entry = this.Entities.Entry(caseStudy);
entry.Property(e => e.CaseStudyName).IsModified = true;
entry.Property(e => e.CaseStudyTitle).IsModified = true;
}
else
{
this.Entities.CaseStudies.Add(caseStudy);
caseStudy.CreatedByRefId = this.UserRefId;
caseStudy.CreatedTime = DateTime.Now;
}
caseStudy.LastModifiedByRefId = this.UserRefId;
caseStudy.LastModifiedTime = DateTime.Now;
if (caseStudy.CaseStudyStatus != (int)CaseStudyStatus.Personalized)
{
caseStudy.CaseStudyStatus = (int)CaseStudyStatus.PendingApproval;
}
caseStudy.ApprovedByRefId = null;
caseStudy.ApprovedTime = null;
this.Entities.SaveChanges();
var existingAdditionalMaterialRefIds = caseStudy.AdditionalMaterials
.Select(m => m.AdditionalMaterialRefId)
.ToArray();
var additionalMaterialsToRemove = this.Entities.AdditionalMaterials
.Where(m =>
m.CaseStudyRefId == caseStudy.CaseStudyRefId &&
!existingAdditionalMaterialRefIds.Contains(m.AdditionalMaterialRefId))
.ToArray();
foreach (var additionalMaterialToRemove in additionalMaterialsToRemove)
{
this.Entities.AdditionalMaterials.Remove(additionalMaterialToRemove);
}
this.Entities.SaveChanges();
}