2

EF5 CodeFirst を試していますが、簡単なセットアップが機能しません ;(

Foo と Bar の 2 つのクラスがあり、Bar はルックアップ テーブルを表します。

public class Foo
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual Bar Bar { get; set; }

}

public class Bar
{
    public int Id { get; set; }
    public string Description { get; set; }
}

public class MyDbContext : DbContext
{
    static MyDbContext()
    {
        Database.SetInitializer<MyDbContext>(null);
    }

    public MyDbContext(): base("testEF"){}

    public DbSet<Foo> Foos { get; set; }
    public DbSet<Bar> Bars { get; set; }
}

これで、DataAccess レイヤーとして機能する静的クラスを作成しました。実際のアプリケーションでは、異なる物理層に配置されます。

public static class DataAccess
{
    public static Bar GetBarById(int id)
    {
        using (var db = new MyDbContext())
        {
            return db.Bars.SingleOrDefault(b => b.Id == id);
        }
    }

    public static Foo InsertFoo(Foo foo)
    {
        using (var db = new MyDbContext())
        {
            db.Foos.Add(foo);

            db.SaveChanges();
        }
        return foo;
    }
}

シード メソッドで DB を初期化しています。

internal sealed class Configuration : DbMigrationsConfiguration<testEF.MyDbContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
    }
    protected override void Seed(testEF.MyDbContext context)
    {
            context.Bars.AddOrUpdate(
                new Bar { Description = "Bar_1" },
                new Bar { Description = "Bar_2" }

                );
    }
}

これにより、Bars テーブルに 2 つのレコードが作成されます。ここまでは順調ですね...

これが私の主な機能です

static void Main(string[] args)
{
    var bar1 = DataAccess.GetBarById(1); 

    var foo = new Foo
    {
        Name = "Foo_1",
        Bar = bar1
    };

    DataAccess.InsertFoo(foo);

}

アプリが実行された後、Foos テーブルにレコードがあります。

Id       Name    Bar_Id
1        Foo_1   3   

なぜ Bar_Id は 3 なのですか? EF は実際に Bars テーブルに新しいレコードを挿入しました!

Id  Description
1   Bar_1
2   Bar_2
3   Bar_1

私が間違っていることは何ですか?

更新: 回避策を見つけました - レコードを挿入する前に Bar プロパティを添付します:

public static Foo InsertFoo(Foo foo)
{
    using (var db = new MyDbContext())
    {
        db.Bars.Attach(foo.Bar);

        db.Foos.Add(foo);

        db.SaveChanges();
    }
    return foo;
}

現在は機能していますが、これは有効なソリューションというよりはハックのようなものです...実際のアプリケーションでは、オブジェクトの複雑さが大きな問題になる可能性があります。私はより良い解決策を受け入れます

4

2 に答える 2

5

問題は、それbar1が別のデータ コンテキストに由来することです。メソッドInsertFooは、 との関係を構築することにより、暗黙的にそれを 2 番目のコンテキストに追加しますFoo。これら 2 つでコンテキストを共有する必要があります。Mainしたがって、メソッドのスコープ全体に対して単一のコンテキストを使用してください。

于 2012-11-14T20:42:35.767 に答える
0

あなたが言及した複雑さ (私はあなたに同意します) は、データ アクセス コンポーネントに静的クラスを使用することによって引き起こされます。メソッド呼び出し全体で DBContext を分離する必要があります。そのようにする代わりに、通常のクラスを作成して、コンストラクターでコンテキストを構築してみませんか。

これにより、もう foo.Bar をアタッチする必要はありません。

public class DataAccess
{
    private MyDbContext _context;

    public DataAccess(){
        _context = new MyDbContext();
    }

    public Bar GetBarById(int id)
    {
        return _context.Bars.SingleOrDefault(b => b.Id == id);
    }

    public Foo InsertFoo(Foo foo)
    {
        _context.Foos.Add(foo);

        _context.SaveChanges();

        return foo;
    }
}

これに基づいて構築し、強化する方法はたくさんあります。呼び出される MyDbContext のインターフェイスを作成IDbContextし、DI フレームワークを使用してこのクラスに挿入することができます。同様に、DataAccessクラスに対して同じことを行い、それを必要な場所に注入することができます。

于 2012-11-14T21:47:36.623 に答える