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

Ric*_*ard 11 entity-framework entity-framework-5

当我尝试同时添加一个包含多个子节点的实体时,我在使用EF重新排序插件时遇到问题.我有一个3级结构,每个(Outer 1--* Item 1--* SubItem)之间有一对多的关系.如果我尝试插入带有Items和Subitems的新Outer,则包含SubItems的Items最终会被插入.

示例代码(.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
    }
}
Run Code Online (Sandbox Code Playgroud)

我知道Alex James这个答案,其中指出插入可能需要重新排序以满足关系约束,但这不是问题.他的回答还提到他们无法跟踪保存订单的结构中的项目顺序,例如列表.

我想知道的是我如何才能订购这些刀片.虽然我可以依靠通过除PK以外的字段对插入的项目进行排序,但如果我可以依赖PK顺序,它会更有效率.我真的不想使用多个SaveChanges调用来完成此任务.

我正在使用EF5 RC,但从其他未解决的问题来看,这已经有一段时间了!

Lad*_*nka 7

我想知道的是我如何才能订购这些刀片.

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

根据评论进行编辑:

是的,这是低级别的交互,因为在使用您无法控制的抽象时,您会对SQL命令的顺序产生期望.在高层次上,你会得到不同的东西,因为你正在使用那些不能用于抽象的期望.如果要控制SQL命令的顺序,则必须通过逐个保存项目(=>多个SaveChangesTransactionScope)来强制执行EF,或者自己编写SQL.否则使用单独的列进行排序.

顺便说一句.EF不会像您看到的那样保存实体.它有自己的更改跟踪器,包含对所有附加实例的引用.引用保存在多个Dictionary实例中,字典不保留插入顺序.如果这些集合用于生成SQL命令(我猜它们是),则无法保证订单.

  • 我不认为这是一种低级别的互动.我要求存储一个有序集,它没有这样做.从很高的层面来说,我得到的东西与我投入的东西有所不同. (2认同)

Jer*_*oen 2

数据库中的表是集合。这意味着订单无法保证。我假设在您的示例中您希望结果按“数字”排序。如果这就是您想要的,如果该数字发生变化并且它不再反映数据库中的顺序,您将怎么做?

如果您确实希望按特定顺序插入行,那么多个 SaveChanges 是您的最佳选择。

没有人愿意多次调用 SaveChanges 的原因是因为这感觉就是这样:一个肮脏的黑客。

由于主键是一个技术概念,因此无论如何在该键上对结果进行排序都不应该具有任何功能意义。您可以按特定字段对结果进行排序,并为此使用数据库索引。您可能不会看到速度上的差异。

明确顺序还有其他好处:对于必须维护它的人来说更容易理解。否则,该人必须知道主键排序很重要并给出正确的结果,因为在应用程序的其他(完全)不相关的部分中,它意外地与数字字段的顺序相同。

  • 我的问题不是我是否应该使用主键进行排序 - 我只是希望能够做到这一点。我的示例大大简化了,实际实现类似于日志文件 - 条目会随着时间的推移而添加,并且永远不会更新或删除。是的,我可以将索引粘贴到另一列(本例中为 Number),但这意味着我使用 2 个索引来完成可以用 1 个索引完成的任务。 (5认同)