概要: Code First と EF 5.0 を使用して MVC ASP.Net アプリに取り組んでいます。Scripts と ScriptItems の 2 つのテーブルがあります。スクリプトは、複数の ScriptItem を持つことができます。ScriptItem も階層的です。ScriptItems はオプションで互いに属することができますが、この関係はありがたいことに 1 レベルの深さしかありません。この関係は、ScriptItem.ParentId によって示されます。
問題: ScriptItems を使用して新しいスクリプト エントリを作成すると、問題なく動作します。ScriptItems を既存のスクリプトに追加しようとすると、問題が発生します。ParentId を持たない ScriptItems を追加しようとすると、すべて正常に動作します。ParentId を持つ ScriptItem を追加しようとするとすぐに、FK 違反の例外が発生します。
詳細:
スクリプト クラス:
public class Script
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Type { get; set; }
[ForeignKey("ProcessorId")]
public Processor Processor { get; set; }
public int ProcessorId { get; set; }
public string Owner { get; set; }
public DateTime Created { get; set; }
public bool Public { get; set; }
public List<ScriptItem> Items { get; set; }
public List<ScriptRun> Runs { get; set; }
public Script()
{
Items = new List<ScriptItem>();
Created = DateTime.Now;
}
}
ScriptItem クラス: (簡潔にするために切り詰められています)
public class ScriptItem
{
[Key]
public int Id { get; set; }
[ForeignKey("ParentId")]
public ScriptItem Parent { get; set; }
public int? ParentId { get; set; }
public Script Script { get; set; }
[ForeignKey("Script")]
public int ScriptId { get; set; }
スクリプト項目を追加する関数:
private void addToScript(ScriptModel model, List<int> ids)
{
Script script = scriptRepository.GetScriptWithItems(model.ScriptId);
List<History> historyItems = historyRespository.History.Where(h => ids.Contains(h.Id)).ToList();
ScriptItem lastScriptItem = script.Items.OrderByDescending(item => item.SortIndex).FirstOrDefault();
int topSortIndex = lastScriptItem == null ? 0 : lastScriptItem.SortIndex;
if (script != null)
{
List<ScriptItem> newItems = new List<ScriptItem>();
Mapper.CreateMap<History, ScriptItem>();
foreach (History h in historyItems)
{
ScriptItem scriptItem = new ScriptItem();
Mapper.Map(h, scriptItem); //Populate new ScriptItem from History entry
scriptItem.SortIndex = ++topSortIndex;
scriptItem.ScriptId = model.ScriptId;
scriptItem.Script = script;
//Only add an entry if it is NOT the parent of another entry. Otherwise, EF will duplicate the Parent entries
if (!historyItems.Any(his => his.ParentId == h.Id))
newItems.Add(scriptItem);
}
scriptRepository.AddScriptItems(newItems);
}
}
最後に、scriptRepository.AddScripItems():
public void AddScriptItems(List<ScriptItem> items)
{
items.ForEach(item => context.Entry(item).State = System.Data.EntityState.Added);
context.SaveChanges();
}
2 つの ScriptItem A と B を既存のスクリプトに追加するシナリオを考えてみましょう。A は B の親です。SQL Server トレースを実行すると、親レコード A を挿入しようとしましたが、ScriptId が 0 であるため、FK 違反例外が発生しました。ScriptId が 0 である理由がわかりません。ScriptId は ScriptItems で適切に設定されています。これをデバッガで確認しました。
上記の addToScript 関数と非常によく似ているため、新しいスクリプトと項目を挿入する関数は含めませんでした。そして、それはうまくいきます。でも、誰かが見たいなら、私もそれを追加できます。
私より頭のいい人にアイデアはありますか?ありがとう!