【问题标题】:Update a single row using Entity Framework - when using entity mapping使用实体框架更新单行 - 使用实体映射时
【发布时间】:2017-01-29 23:36:22
【问题描述】:

我正在尝试使用实体框架代码优先更新数据库中的单个值。

它抛出以下错误:

附加类型的实体 'WarehouseAPI.Core.DataEntities.Models.TaskDetail' 失败,因为 另一个相同类型的实体已经具有相同的主键 价值。使用“附加”方法或设置 如果实体中有任何实体,则实体的状态为“未更改”或“已修改” 图有冲突的键值。这可能是因为某些实体 是新的,尚未收到数据库生成的键值。在 这种情况下使用 'Add' 方法或 'Added' 实体状态来跟踪 图表,然后将非新实体的状态设置为“未更改”或 酌情“修改”。

[Table("tblTaskDetail")]
public partial class tblTaskDetail
{
    [Key]
    public int TaskDetailID { get; set; }

    public int? ScheduleId { get; set; }

    [Required]
    [StringLength(50)]
    public string RobotID { get; set; }

    public Guid? SessionID { get; set; }

    [Required]
    [StringLength(50)]
    public string TaskStatus { get; set; }

    [Column(TypeName = "datetime2")]
    public DateTime? TaskScheduledOn { get; set; }

    [StringLength(250)]
    public string TaskSummary { get; set; }

    [Column(TypeName = "datetime2")]
    public DateTime? TaskStartedOnUtc { get; set; }

    [Column(TypeName = "datetime2")]
    public DateTime? TaskCompletedOnUtc { get; set; }
}

public class TaskDetail
{
    public int TaskDetailID { get; set; }
    public int? ScheduleId { get; set; }
    public string RobotID { get; set; }
    public Guid? SessionID { get; set; }
    public string TaskStatus { get; set; }
    public DateTime TaskScheduledOn { get; set; }
    public string TaskSummary { get; set; }
    public DateTime TaskStartedOnUtc { get; set; }
    public DateTime TaskCompletedOnUtc { get; set; }
}

public class TaskDetailMapper:EntityTypeConfiguration<TaskDetail>
{
    public TaskDetailMapper()
    {
        this.ToTable("tblTaskDetail");
        this.HasKey(hk => hk.TaskDetailID);
        this.Property(o => o.RobotID).HasColumnName("RobotID");
        this.Property(o => o.ScheduleId).HasColumnName("ScheduleId");
        this.Property(o => o.SessionID).HasColumnName("SessionID");
        this.Property(o => o.TaskCompletedOnUtc).HasColumnName("TaskCompletedOnUtc");
        this.Property(o => o.TaskDetailID).HasColumnName("TaskDetailID");
        this.Property(o => o.TaskScheduledOn).HasColumnName("TaskScheduledOn");
        this.Property(o => o.TaskStartedOnUtc).HasColumnName("TaskStartedOnUtc");
        this.Property(o => o.TaskStatus).HasColumnName("TaskStatus");
        this.Property(o => o.TaskSummary).HasColumnName("TaskSummary");
    }
}

public partial class WarehouseAPIContext : DbContext
{
    public WarehouseAPIContext() : base("name=WarehouseAPIContext")
    {
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new TaskDetailMapper());
    }
}

public class TaskDetailRepository:APIRepository<TaskDetail>
{
    WarehouseAPIContext _context;

    public TaskDetailRepository(WarehouseAPIContext context):base(context)
    {
        _context = context;
    }

    public TaskDetail UpdateTaskStartingTime(TaskDetail entity)
    {
        try
        {
            var taskDetail = new TaskDetail() { TaskStartedOnUtc = entity.TaskStartedOnUtc, TaskStatus = entity.TaskStatus,SessionID = entity.SessionID, TaskDetailID = entity.TaskDetailID };

             dbSet.Attach(taskDetail);    // THROWS THE ERROR
            _context.Entry(taskDetail).Property(x => x.TaskStartedOnUtc).IsModified = true;
            _context.SaveChanges();

            return entity;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
}

public class APIRepository<T> where T:class
{
        internal WarehouseAPIContext wContext;
        internal DbSet<T> dbSet;

        public APIRepository(WarehouseAPIContext context)
        {
            wContext = context;
            dbSet = context.Set<T>();
        }

        public virtual T Update(T entity)
        {
            try
            {
                var entry = wContext.Entry(entity);
                dbSet.Attach(entity);
                entry.State = EntityState.Modified;
                wContext.SaveChanges();
                return entity;
            }
            catch (Exception ex)
            {
                //ExceptionHandler.Handle(ex);
                return null;
            }
        }
}

【问题讨论】:

  • 该实体是否已在上下文缓存中可用?您是否在同一上下文中的其他位置从数据库中加载该实体?还有为什么有两个上下文对象 - dbSet_context。我认为,当您使用.Entry 时,您可以跳过.Attach 部分

标签: c# asp.net entity-framework


【解决方案1】:

有两种方法可以做到这一点,首先加载要更新的实体,将更改复制到此实体并保存更改,我更喜欢,第二种选择是加载要更新的实体,然后解除附加它,并将其附加回来,最后保存上下文更改。

您无法附加已附加的实体,EF 将再次插入该对象

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-10
    • 2010-10-14
    • 2010-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-11
    相关资源
    最近更新 更多