0

私は、標準の 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) #>)]
<#+
    }
}

それが役立つことを願っています!

4

1 に答える 1

1

AddressId がリレーションの FK として処理されないため、BillingAddress が正しくマッピングされていないようです。

この属性をナビゲーション プロパティに追加してみてください。

[ForeignKey("AddressId")]
public Address BillingAddress { get;set; }

データベースで EDMX を使用している場合は、最初にそれらのクラス間に正しく構成された関係があることを確認してください。EF はこの情報をストア マッピングで使用し、ストア マッピングは操作のシーケンスを定義します。正しく構成されていない場合、関連エンティティはタイプ名のアルファベット順に処理されます => のAccount前に処理されAddressます。

ところで。通話Account中に重複していないことを確認していますか?SaveChanges

于 2012-04-27T08:29:49.033 に答える