2

我正在尝试 EF5 CodeFirst,但无法进行简单的设置;(

我有两个类 Foo 和 Bar,其中 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; }
}

现在我创建了一个用作数据访问层的静态类 - 在实际应用程序中,它将位于不同的物理层

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;
    }
}

我正在使用种子方法初始化数据库:

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 表中创建两条记录。到现在为止还挺好...

这是我的主要功能

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;
}

它现在正在工作,但这更像是一种 hack 而不是一个有效的解决方案......在现实世界的应用程序中,对象的复杂性可能成为一个巨大的问题。我愿意接受更好的解决方案

4

2 回答 2

5

问题是bar1来自不同的数据上下文。您的InsertFoo方法通过与Foo. 您希望这两个共享一个上下文。因此,对方法的整个范围使用单个上下文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 回答