【问题标题】:Get the database ID (IDENTITY COLUMN) of newly created entity before context.SaveChanges()在 context.SaveChanges() 之前获取新创建实体的数据库 ID(IDENTITY COLUMN)
【发布时间】:2013-06-04 12:31:38
【问题描述】:

是否可以使用实体框架为数据库中要添加的行保留 IDENTITY 值?

在我对ObjectContext.SaveChanges 的覆盖中,我想做这样的事情:

public override int SaveChanges(SaveOptions options)
{
    var affectedEntities = ObjectStateManager.GetObjectStateEntries(
        EntityState.Added |
        EntityState.Modified |
        EntityState.Deleted);

    foreach (var entry in affectedEntities)
    {
        var type = GetObjectType(entry.Entity.GetType());

        if (entry.State == EntityState.Added)
        {
            // log the creation of the new entity into a log file
            // or a different table. For this, I need the newly
            // created entity's ID. Is it possible?
        }
    }

    return base.SaveChanges(options);

    // if I check for ObjectState here, i.e. after SaveChanges, 
    // it won't work? Because once the changes are committed to the database
    // the newly added object's state would no longer remain
    // Added.
}

【问题讨论】:

    标签: sql-server sql-server-2008 entity-framework entity-framework-4 ado.net


    【解决方案1】:

    您不能要求数据库预先分配 id。你有两个选择

    1. 实现您自己的身份服务器
    2. 数据写入数据库后获取id

    这是选项 2 的几个示例。它们都做同样的事情 - 在调用 SaveChanges() 之前构建添加项目的列表并在之后迭代它们。

    public interface IIDentifiable
    {
        int id { get; set; }
    }
    
    public override int SaveChanges()
    {
        ChangeTracker.DetectChanges();
        List<IIDentifiable> addedObjects = GetNewEntries();
        int result = base.SaveChanges();
        foreach (IIDentifiable o in addedObjects)
        {
            //log o.id
        }
        return result;
    }
    
    private List<IIDentifiable> GetNewEntries()
    {
        var result = (
            from e in ChangeTracker.Entries()
            where e.State == System.Data.EntityState.Added
            select e.Entity)
            .OfType<IIDentifiable>()
            .ToList();
    
        return result;
    }
    

    IIDentifiable 的缺点是获取其他详细信息,例如 Type 等。

    第二种选择是做同样的事情,但使用dynamic而不是IIDentifiable

    public override int SaveChanges()
    {
        ChangeTracker.DetectChanges();
        List<dynamic> addedObjects = GetNewEntries();
        int result = base.SaveChanges();
        foreach (dynamic o in addedObjects)
        {
            //log o.id
            //log o.GetType()
        }
        return result;
    }
    
    private List<dynamic> GetNewEntries()
    {
        var result = (
            from e in ChangeTracker.Entries()
            where e.State == System.Data.EntityState.Added
            select e.Entity)
            .ToList();
    
        return result;
    }
    

    【讨论】:

    • 太棒了。基本上,您是在说,“只需将内容缓存在列表中,然后再从它们中读取。”谢谢你。我实施了你的建议,它奏效了。惊人的。非常感谢。 :-) 我刚刚做了一个 ToList()。我没有使用任何接口,因为因为 C# 不是鸭子类型,所以这会强制我的模型对象从该接口显式继承。因为成本,我也没有使用动态,因为我想要的只是在那里,它们的类型是已知的。非常感谢。
    猜你喜欢
    • 2014-11-17
    • 2016-03-27
    • 2013-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多