7

使用 .NET 4、MVC 4、Entity Framework 5、SQL Server;

我想在一个事务中插入一个新的 Header 记录和几个新的 HeaderData 记录,它们都具有插入的 Header 记录的外键。标头记录有一个 Identity int Primary Key。

Entities.Header h = new Entities.Header();

h.Name = name;
h.Time = DateTime.Now;
h.Comments = comments;

db.Headers.Add(h);
// db.SaveChanges(); // Save changes here?
// and get ID to use below via h.ID?

foreach (DataRecord dr in datarecords) // my own custom types here
{
    Entities.HeaderData hd = new Entities.HeaderData();
    // hd.header = thisid // ?? this is the FK to Header.ID, its Identity int PK
    hd.name = dr.name
    hd.value = dr.value

    db.HeaderDatas.Add(hd)
}

db.SaveChanges(); // or wait to save all here? 

所以问题是,在提交之前,我不知道将什么标题记录 ID 放入数据记录的 FK 字段中。还是我?只是在 SaveChanges/Commit 之前引用 h.ID 不起作用,它返回 0。

选项:1)我是否应该先提交标头记录,使用 PK,然后填充数据记录模型并分别提交?在这种情况下可能必须回滚标头,这听起来不是最佳的方法。

2)我应该使用 GUID PK 或类似的代替,我在应用程序的此处创建它吗?无论如何,这是唯一可以添加记录的地方。

3) Entity Framework 中是否有一种巧妙的方法(可能是临时 EntityKey?),并让它进行事务插入,以便它自动将正确的标题 ID 放入数据记录的 FK 字段中?这对 EF 来说似乎是可行的,但我无法完全找到对它的引用。

4

2 回答 2

9

如果Header并且HeaderData通过外键(一对多)关系相关,您应该在其中有一个导航集合Header.HeaderDatas(类型ICollection<HeaderData>或其他集合类型)Header或导航引用HeaderData.Header(类型Header),HeaderData甚至两者都有。

无论哪种情况,更好的方法是使用这些导航属性建立关系:

Entities.Header h = new Entities.Header();
h.HeaderDatas = new List<HeaderData>();
// ...
foreach (DataRecord dr in datarecords)
{
    Entities.HeaderData hd = new Entities.HeaderData();
    //...
    h.HeaderDatas.Add(hd)
}
db.Headers.Add(h);
db.SaveChanges();

或者:

Entities.Header h = new Entities.Header();
// ...
foreach (DataRecord dr in datarecords)
{
    Entities.HeaderData hd = new Entities.HeaderData();
    //...
    hd.Header = h;

    db.HeaderDatas.Add(hd);
}
db.SaveChanges();

您不需要直接设置 FK。EF 将正确地将您设置的导航属性“翻译”为数据库表的必要外键值。

于 2013-03-29T17:26:29.717 回答
0

导航属性不是必需的。使用事务并调用 SaveChanges() 两次;添加第一个实体后一次,最后一次。因为 EF 可以有多种不同的使用方式,所以下面的示例可能不是适合您的情况的确切解决方案,但它应该能说明问题。

using (MyContext context = new MyContext())
using (DbContextTransaction txn = context.Database.BeginTransaction())
{
    try
    {
        EntityA a = new EntityA();
        a.Foo = "bar";
        context.A_DbSet.Add(a); // Assuming the use of the DbSet<T> class
        context.SaveChanges();
        // A.ID is now set, but not committed

        EntityB b = new EntityB();
        b.A_ID = a.ID;
        b.Foo2 = "bar2";
        context.B_DbSet.Add(b);
        context.SaveChanges();
        txn.Commit();
    }
    catch (Exception ex)
    {
        txn?.Rollback();
    }
}
于 2017-03-28T16:45:53.633 回答