覆盖SaveChanges()的最佳方法

时间:2014-11-13 11:52:40

标签: c# entity-framework

我们在一个项目上工作了1个月,有6个实体与其他实体没有任何关系。它们都是简单的实体。

我们为每个实体创建了6个不同的操作类。类的SaveOrUpdateEntity()方法几乎与您的想法相同。它是这样的:

public static ErrorType SaveOrUpdateEntity(Entity entity, int userID)
{
    try
    {
        using (DataEntities ctx = new DataEntities())
        {
            if (entity != null)
            {
                if (entity.entityID == 0)
                {
                    entity.CreateDate = DateTime.Now;
                    entity.CreatedBy = userID;

                    ctx.Entry(entity).State = EntityState.Added;
                }
                else
                {
                    entity.ModifyDate = DateTime.Now;
                    entity.ModifiedBy = userID;

                    ctx.Entry(entity).State = EntityState.Modified;
                }
            }

            ctx.SaveChanges();
        }

        return ErrorType.NoError;
    }
    catch (Exception ex)
    {
        return ErrorType.SaveError;
    }

}

如果SaveOrUpdateEntity()方法更短并且通过覆盖SaveChanges()方法更通用,那将非常有用。根据其他关于覆盖SaveChanges()方法的问题,文章和帖子,实现存储实体状态的接口是一个很好的解决方案,但我也想知道其他解决方案。

因为我是新手,所有的答案都会非常感激。

谢谢。

3 个答案:

答案 0 :(得分:11)

您可以执行以下操作

1-在您的应用程序中创建一个接口,所有具有以下属性的类都将实现此接口:Id,CreatedDate,CreatedBy,ModifiedDate,ModifiedBy

public interface ITrack
{
      int Id{get; set;}
      int CreatedBy{get; set;}
      DateTime CreatedDate{get; set;}
      int? ModifiedBy{get; set;} // int? because at first add, there is no modification
      DateTime? ModifiedBy {get; set;}
}
  

最佳做法CreatedByModifiedBy定义为string,这将有助于提高性能和维护

2-添加实现接口TrackableEntry

的类ITrack
public abstract class TrackableEntry : ITrack
{
      public int Id{get; set;}
      public int CreatedBy{get; set;}
      public DateTime CreatedDate{get; set;}
      public int? ModifiedBy{get; set;} 
      public DateTime? ModifiedBy {get; set;}
}

3-从所有类中删除界面中提到的属性,并让这些类直接从TrackableEntry

实现
public class A: TrackableEntry
{
    //public int Id{get; set;}
    //public int CreatedBy{get; set;}
    //public DateTime CreatedDate{get; set;}
    //public int? ModifiedBy{get; set;}
    //public DateTime? ModifiedBy {get; set;}
}

4-在您的DbContext文件中覆盖SaveChanges并添加媒体资源UserIdUserName,如果您关注*Best practices*部分

public int UserId{get; set;}

public override int SaveChanges()
{
    this.ChangeTracker.DetectChanges();
    var added = this.ChangeTracker.Entries()
                .Where(t => t.State == EntityState.Added)
                .Select(t => t.Entity)
                .ToArray();

    foreach (var entity in added)
    {
        if (entity is ITrack)
        {
            var track = entity as ITrack;
            track.CreatedDate = DateTime.Now;
            track.CreatedBy = UserId;
        }
    }

    var modified = this.ChangeTracker.Entries()
                .Where(t => t.State == EntityState.Modified)
                .Select(t => t.Entity)
                .ToArray();

    foreach (var entity in modified)
    {
        if (entity is ITrack)
        {
            var track = entity as ITrack;
            track.ModifiedDate = DateTime.Now;
            track.ModifiedBy = UserId;
        }
    }
    return base.SaveChanges();
}

如果您想调用SaveChanges方法,最后在表单中,请确保设置UserIdUserName

var entities=new Entities(); // assuming that your DbContext file called Entities
// code for adding or deletion or modification here
entities.As.Add(new A(){...});

// ....

entities.UserId=MyUser;
entities.SaveChanges();

希望这会对你有所帮助

答案 1 :(得分:1)

使用以下代码会更好:

    var added = this.ChangeTracker.Entries()
            .Where(t => t.Entity is ITrack && t.State == EntityState.Added)
            .Select(t => t.Entity)
            .ToArray();

修改后也一样:

    var modified = this.ChangeTracker.Entries()
            .Where(t => t.Entity is ITrack && t.State == EntityState.Modified)
            .Select(t => t.Entity)
            .ToArray();

并删除foreach循环中的条件...

答案 2 :(得分:0)

要“覆盖” SaveChanges,而无需创建所有额外的代码,我将其包装在其自己的扩展方法中。即

public static int SaveChangesWrapped(this MyDbContext db)
{
    // do other things

    return db.SaveChanges();
}

或异步...

public static Task<int> SaveChangesAsyncWrapped(this MyDbContext db)
{
    // do other things

    return await db.SaveChangesAsync();
}

您可以根据需要进行调整,即添加其他参数,使其通用,等等。我可能遗漏了一些东西,但这足以让我“覆盖” SaveChanges,并减少了很多重复代码。

然后,在代码中任何要保存的地方,就是:

db.SaveChangesWrapped();

//or

await db.SaveChangedAsyncWrapped();