实体框架在不应该执行的地方执行INSERT

时间:2016-08-07 11:13:16

标签: c# asp.net-mvc entity-framework entity-framework-6

我有以下实体数据模型,为简洁而简化;

public abstract class Entity<T> : BaseEntity, IEntity<T>
{
    [Key]
    public virtual T Id { get; set; }
}

public class User : Entity<int>
{
    public List<Category> Categories { get; set; } 
}

public class Category : Entity<int>
{
    public string Description { get; set; } 
}


public class List : Entity<int>
{
    public Category Category { get; set; } 
}

可以使用DbContext从DbContext访问这些内容,这些DbContext由通用服务或更自定义的实现公开,以提供业务逻辑。

当我发布数据库并将以下代码添加到Seed()方法时,一切都很好,数据直接在数据库中看起来很好。

 var user = new User
        {
            Email = "",
            Categories = new List<Category>
                {
                    new Category
                    {
                        Description = "Category 1",
                    },
                    new Category
                    {
                        Description = "Category 2",
                    }
                }
        };


context.Users.AddOrUpdate(u => u.Email, user);

   var list = new List()
            {
                Id = 1,
                Description = "Test List",
                UserId = 1,
                Category = user.Categories.FirstOrDefault()
            };

            context.Lists.AddOrUpdate(u =>u.Id, list);

请注意,用户拥有类别,您可以(应该只能)通过访问Categories属性来创建它们。

这给了我;

Categories post-Seed

Lists post-Seed

我在控制器中使用这些对象;

 public ActionResult Edit(int id)
        {
            var categories = _usersService.GetUser(User.Id).Categories;
            categories.Insert(0, new Category {Description = "", Id = 0});

            var list = _listsService.GetList(id);

            var viewModel = new EditViewModel
            {
                Id = list.Id,
                Reference = list.Reference,
                Description = list.Description,
                CategoryId = list.Category?.Id ?? 0,
                Categories = new SelectList(categories.AsEnumerable(), "Id", "Description")
            };

            return View(viewModel);
        }

在上面的测试中,我使用种子期间插入的List,我可以看到List确实有Category,且值正确。

enter image description here

有关信息,我使用的是以下ViewModel。我一直在调查方法,以便能够选择&#39;来自DropDown的User.Categories,这似乎目前效果最佳。

  public class EditViewModel
    {
        [Required]
        public int Id { get; set; }

        [Required]
        public string Description { get; set; }

        public IEnumerable<SelectListItem> Categories { get; set; }

        [ScaffoldColumn(false)]
        public int CategoryId { get; set; }

        [ScaffoldColumn(false)]
        public Guid Reference { get; set; }
    }

填充的ViewModel看起来像这样;

enter image description here 最后,POST方法;

 [HttpPost]
        public ActionResult Edit(EditViewModel model)
        {
            if (ModelState.IsValid)
            {
                var categories = _usersService.GetUser(User.Id).Categories;

                var list = _listsService.GetList(model.Id);

                list.Description = model.Description;
                list.Category = categories.FirstOrDefault(x => x.Id == model.CategoryId);

                _listsService.Update(list);

                categories.Insert(0, new Category { Description = "", Id = 0 });
                model.Categories = new SelectList(categories.AsEnumerable(), "Id", "Description");

                return View(model);
            }

            return View(model);
        }

因此,在以下场景中,会发生这种情况。为清楚起见,每次我这样做,我都会回到列表索引并再次获得编辑;

  • 选择&#39;&#39;来自下拉列表 - 没有类别INSERT,仅在列表上更新,设置[Category_Id] = NULL - 更正
  • SELECT&#39; Category 1&#39;来自DropDown。 INSERT类别,UPDATE列表 - NOT Correct

用于更新List的代码是;

public void Update(T entity)
{
    if (entity == null) throw new ArgumentNullException(nameof(entity));
    _context.Entry(entity).State = EntityState.Modified;
    _context.SaveChanges();
}

现在,我知道这是我正在做的事情,但对EF来说是新手,我不知道。

enter image description here

4 个答案:

答案 0 :(得分:1)

问题在于如何设定价值。

我需要设置外键并为此值赋值。

public class List : Entity<int>
{
    public int CategoryId { get; set; }

    [ForeignKey("CategoryId")
    public Category Category { get; set; } 
}

然后将值设置为

var list = _listsService.GetList(model.Id);
list.Description = model.Description;
list.CategoryId = model.CategoryId;
list.Category = null;
_listsService.Update(list);

在此之后,从存储库中获取列表时,将正确填充Category和CategoryID。

问题在于将实体设置为已修改,这内部表明该类别为“新”,而实际上并非如此。你也可以'附加'和现有的类别到实体/上下文,但决定上面的方法更好。

稍微好一点的方法是创建一个新的'UpdateList'方法,可以调用它而不是通用更新。此方法将在控制器方法之外执行相关属性的设置。

答案 1 :(得分:0)

问题可以在视野中,你没有我将EF添加新记录而不是更新现有记录。

答案 2 :(得分:0)

一般情况下:在为自定义类命名时(例如List),请注意现有的类:

public class List : Entity<int>
{
    public Category Category { get; set; } 
}

请注意,您在正确的命名空间中使用了正确的类。

var user = new User
    {
        Email = "",
        Categories = new YourOwnNamespace.List<Category>
            {
                new Category
                {
                    Description = "Category 1",
                },
                new Category
                {
                    Description = "Category 2",
                }
            }
    };

避免将类和属性命名为现有名称。在例如,更改List课程'MYLIST'。

答案 3 :(得分:-1)

我不确定,但您可以编写更新方法,如下所示:

public void Update(T entity)
{
    if (entity == null) throw new ArgumentNullException(nameof(entity));
    var item = _collection.Find(item.Id);

    if (item == null) throw new ArgumentNullException(nameof(item ));
    _context.Entry(item).CurrentValues.SetValues(entity);
    _context.SaveChanges();
}