我正在尝试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; }
}
现在我已经创建了一个用作DataAccess Layer的静态类 - 在实际应用程序中它将位于不同的物理层上
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;
}
它现在正在运行,但这更像是一个黑客而不是一个有效的解决方案...... 在实际应用中,对象的复杂性可能成为一个巨大的问题。 我愿意接受更好的解决方案
答案 0 :(得分:5)
问题是bar1
来自不同的数据上下文。您的InsertFoo
方法通过与Foo
建立关系,将其隐式添加到第二个上下文中。您希望这两者共享一个上下文。因此,对Main
方法的整个范围使用单个上下文。
答案 1 :(得分: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;
}
}
您可以通过多种方式进行构建和增强。您可以为名为IDbContext
的MyDbContext创建一个接口,并使用DI框架将其注入此类。同样,您可以对DataAccess
类执行相同操作,并将其注入需要的任何位置。