私は、標準の T4 テンプレートを使用して DbContext と POCO を生成する、EF 4.2 とデータベース ファースト開発を使用するアプリケーションに取り組んでいます。T4 テンプレートは、次のようなエンティティを生成します。
public class Address
{
public int AddressId { get;set; }
public string Address1 { get;set; }
public string City { get;set; }
}
public class Account
{
public int AccountId { get;set; }
public string Name { get;set; }
public int AddressId { get;set; }
public Address BillingAddress { get;set; }
}
既存のアカウントの請求先住所を作成すると、コードは次のようになります。
public void Save(Account updated)
{
var existing = DbContext.Find(updated.AccountId);
MyContext.Entry(existing).CurrentValues.SetEntry(updated);
existing.Address = updated.Address;
MyContext.SaveChanges();
}
SQL Server Profiler を見ると、アドレス エントリがデータベースに挿入されていることがわかりますが、残念ながら、アカウント エントリが更新された後に発生しているため、アドレスは親アカウントから切り離されており、次にアカウントを読み込むと、請求が行われます。アドレスは再び空です。
回避策は、SaveChanges() の呼び出しの後に次のコードを追加することです。
if (existing.AddressId == null && existing.Address != null)
{
existing.AddressId = existing.Address.AddressId;
MyContext.SaveChanges();
}
これは機能するかもしれませんが、データベースへの 2 回目の SQL UPDATE が必要であり、エンティティが成長してより多くの関連付けが追加されるにつれて、ますます多くのハックが必要になります。私が行方不明であることは明らかですか?
**更新** 以下の Ladislav の回答に従って、WriteNavigationProperty の次のメソッドへの呼び出しを T4 テンプレートに追加しました。
void WriteKeyAttribute(CodeGenerationTools code, NavigationProperty navigationProperty, MetadataTools ef)
{
var dependentProperties = navigationProperty.GetDependentProperties();
if (dependentProperties.Any())
{
var keys = new List<string>();
foreach (var key in dependentProperties)
{
keys.Add(String.Format("\"{0}\"", key.Name));
}
#>
[ForeignKey(<#= String.Join(", ", keys) #>)]
<#+
}
}
それが役立つことを願っています!