且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

实体框架中多个记录的插入顺序

更新时间:2023-02-13 11:10:26


我想知道的是我能得到什么这些插入要被订购。


你不能。数据库命令的顺序是EF的内部行为。如果要控制命令的顺序不要使用从低级数据库交互中抽象出的工具 - 直接使用SQL。



根据评论编辑:



是的,这是低级别的互动,因为你期待的顺序是使用抽象处理SQL命令时,您无法控制。在高层次上,你会得到不同的东西,因为你正在使用不符合这种抽象的期望。如果要控制SQL命令的顺序,您必须通过一个一个地保存项目来强制EF(=>多个 SaveChanges TransactionScope )或自己写SQL。否则使用单独的列进行排序。



Btw。 EF不会按照您的看法保存实体。它有自己的更改跟踪器,保留对所有附加实例的引用。参考文献保存在多个字典实例和字典不保留插入顺序。如果这些集合用于生成SQL命令(我猜是这样)就不能保证任何顺序。


I'm having trouble with EF reordering my inserts when I try and add an entity with multiple children all at once. I've got a 3 level structure with one-to-many relationships between each (Outer 1--* Item 1--* SubItem). If I try and insert a new Outer with Items and Subitems, the Items which contain SubItems end up being inserted first.

Sample Code (.NET 4.5, EF 5.0.0-rc):

public class Outer
{
    public int OuterId { get; set; }
    public virtual IList<Item> Items { get; set; }
}

public class Item
{
    public int OuterId { get; set; }
    [ForeignKey("OuterId")]
    public virtual Outer Outer { get; set; }

    public int ItemId { get; set; }
    public int Number { get; set; }

    public virtual IList<SubItem> SubItems { get; set; }
}

public class SubItem
{
    public int SubItemId { get; set; }

    [ForeignKey("ItemId")]
    public virtual Item Item { get; set; }
    public int ItemId { get; set; }
}

public class MyContext : DbContext
{
    public DbSet<Outer> Outers { get; set; }
    public DbSet<Item> Items { get; set; }
    public DbSet<SubItem> SubItems { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        Database.SetInitializer(new DropCreateDatabaseAlways<MyContext>());
        MyContext context = new MyContext();

        // Add an Outer object, with 3 Items, the middle one having a subitem
        Outer outer1 = new Outer { Items = new List<Item>() };
        context.Outers.Add(outer1);
        outer1.Items.Add(new Item { Number = 1, SubItems = new List<SubItem>() });
        outer1.Items.Add(new Item { Number = 2, SubItems = new List<SubItem>(new SubItem[] { new SubItem() }) });
        outer1.Items.Add(new Item { Number = 3, SubItems = new List<SubItem>() });

        context.SaveChanges();

        // Print the order these have ended up in
        foreach (Item item in context.Items)
        {
            Console.WriteLine("{0}\t{1}", item.ItemId, item.Number);
        }
        // Produces output:
        // 1       2
        // 2       1
        // 3       3
    }
}

I'm aware of this answer by Alex James which states that inserts may need to be reordered in order to satisfy relational constraints, but that is not the issue here. His answer also mentions that they can't track the order of items in order-preserving structures such as Lists.

What I'd like to know is how I can get these inserts to be ordered. While I can rely on sorting my inserted items by a field other than the PK, it's a lot more efficient if I can rely on the PK order. I don't really want to have to use multiple SaveChanges calls to accomplish this.

I'm using EF5 RC, but judging by the other unanswered questions around, this has been around for some time!

What I'd like to know is how I can get these inserts to be ordered.

You cannot. Order of database commands is EF's internal behavior. If you want to control the order of commands don't use tools which abstract you from low level database interactions - use SQL directly.

Edit based on comment:

Yes it is low level interaction because you are putting expectations on the order of SQL commands when working with abstraction you don't have under your control. At high level you are getting something different because you are using expectations which don't work with that abstraction. If you want to have control over order of SQL commands you must either force EF by saving items one by one (=> multiple SaveChanges and TransactionScope) or write SQL yourselves. Otherwise use separate column for ordering.

Btw. EF doesn't save the entity as you see it. It has its own change tracker holding references to all your attached instances. References are held in multiple Dictionary instances and dictionary doesn't preserve insertion order. If these collections are used for generating SQL commands (and I guess they are) no order can be guaranteed.