1

私はEntity Framework 4.3を使用しており、新しいエンティティを作成するときにナビゲーションプロパティを設定して既存のエンティティを参照しようとしていますが、save EFを呼び出すと、ナビゲーションプロパティを設定したテーブルにPK違反があると不平を言います(つまり、参照ではなく新しいレコードを作成しています!)。

既存の POCO を参照して EF が新しいデータベース レコードを作成しようとするのではなく、どのように接続できますか (ただし、単に ID を使用するのではなく、理想的には、別のクエリから取得した実際のエンティティを参照したい)?

前もって感謝します、

クリス

public class BusinessUnit
{
    public int BusinessUnitID { get; set; }
    public ExternalPlugin AccountsDataSourceModule { get; set; }
    public ExternalPlugin OptionalContactsDataSourceModule { get; set; }
}

public BusinessUnit NewBusinessUnit(string name, ExternalPlugin accountsModuleId = null, ExternalPlugin contactsModuleId = null)
{
    IUnitOfWork unitOfWork = UnitOfWorkFactory.CreateUnitOfWork();

    BusinessUnit unit = new BusinessUnit();
    unit.CompanyName = name;
    unit .AccountsDataSourceModule = accountsModuleId; // this causes a problem
    unit .OptionalContactsDataSourceModule = contactsModuleId; // as does this
    unitOfWork.BusinessUnitRepository.Insert(unit);

    unitOfWork.Save();
    return unit;
}
4

1 に答える 1

2

既存のエンティティをコンテキストに添付する必要があります。

BusinessUnit unit = new BusinessUnit();
unit.CompanyName = name;

unitOfWork.ExternalPluginRepository.Attach(accountsModuleId);
unitOfWork.ExternalPluginRepository.Attach(contactsModuleId);

unit.AccountsDataSourceModule = accountsModuleId;
unit.OptionalContactsDataSourceModule = contactsModuleId;
unitOfWork.BusinessUnitRepository.Insert(unit);

...しunitOfWork.ExternalPluginRepository.Attach(ExternalPlugin plugin)なければならない場所:

context.ExternalPlugins.Attach(plugin);

すべてのリポジトリが同じコンテキスト インスタンスを使用することを期待しています。Attachプラグインがデータベースに既に存在することを EF に伝え、それらのエンティティの INSERT を回避します。

編集

エラーメッセージが表示される場合...

エンティティ オブジェクトは、IEntityChangeTracker の複数のインスタンスによって参照できません。

...これは、同時に複数のコンテキスト インスタンスにアタッチされているエンティティがあることを意味します。ほとんどの場合、コンテキストが不要になったときに常にコンテキストを破棄することで、これを回避できます。あなたのコード サンプルは、この適切な方法に従っていません。むしろ次のようになります。

public BusinessUnit NewBusinessUnit(string name,
    ExternalPlugin accountsModuleId = null,
    ExternalPlugin contactsModuleId = null)
{
    using (IUnitOfWork unitOfWork = UnitOfWorkFactory.CreateUnitOfWork())
    {
        BusinessUnit unit = new BusinessUnit();
        unit.CompanyName = name;

        unitOfWork.ExternalPluginRepository.Attach(accountsModuleId);
        unitOfWork.ExternalPluginRepository.Attach(contactsModuleId);

        unit.AccountsDataSourceModule = accountsModuleId;
        unit.OptionalContactsDataSourceModule = contactsModuleId;
        unitOfWork.BusinessUnitRepository.Insert(unit);

        unitOfWork.Save();

        return unit;
    }
}

usingブロックの最後で、のDisposeメソッドがunitOfWork自動的に呼び出されます。これを機能させる (そしてコンパイルする) には、IUnitOfWorkインターフェイスを派生IDisposableさせて具象UnitOfWorkクラスに実装する必要があります。

public interface IUnitOfWork : IDisposable
{
    // ...
}

public class ConcreteUnitOfWork : IUnitOfWork, IDisposable
{
    private MyDbContext _context;
    // I assume that you have a member for the DbContext in this class
    // ...

    // implementation of IDisposable
    public void Dispose()
    {
        if (_context != null)
            _context.Dispose();
    }
}
于 2012-05-27T17:47:11.973 に答える