Как выполнить CRUD с Entity Framework Code-First? - PullRequest
6 голосов
/ 09 июня 2011

Мне очень трудно обновлять и удалять многие из многих отношений с EF Code-first.

У меня довольно простая модель:

    public class Issue
    {
        [Key]
        public int      IssueId     { get; set; }
        public int      Number      { get; set; }
        public string   Title       { get; set; }
        public DateTime Date        { get; set; }

        public virtual ICollection<Creator> Creators { get; set; }
    }

    public class Creator
    {
        [Key]
        public int      CreatorId   { get; set; }
        public string   FirstName   { get; set; }
        public string   MiddleName  { get; set; }
        public string   LastName    { get; set; }

        public virtual ICollection<Issue> Issues { get; set; }
    }

    public class Icbd : DbContext
    {
        public DbSet<Issue> Issues { get; set; }
        public DbSet<Creator> Creators { get; set; }
    }

Я не смогвыяснить, как обновить концепцию «многие ко многим», используя контекст EF.В моем действии isnert / update у меня есть этот код:

    [HttpPost]
    public ActionResult EditIssue ( Issue issue, int[] CreatorIds )
    {
        if(CreatorIds == null)
            ModelState.AddModelError("CreatorIds", "Please specify at least one creator");

        if(ModelState.IsValid)
        {
            // insert or update the issue record (no relationship)
            if (issue.IssueId == 0)
                db.Issues.Add(issue);
            else
                db.Entry(issue).State = System.Data.EntityState.Modified;
            db.SaveChanges();

            // delete - delete current relationships
            if (issue.Creators != null)
            {
                issue.Creators = new List<Creator>();
                db.Entry(issue).State = System.Data.EntityState.Modified;
                db.SaveChanges();
            }

            // insert - get creators for many-to-many realtionship
            issue.Creators = db.Creators.Where(x => CreatorIds.Contains(x.CreatorId)).ToList();
            db.Entry(issue).State = System.Data.EntityState.Modified;
            db.SaveChanges();

            return RedirectToAction("Index");
        }

        IssueEditModel issueEdit = new IssueEditModel{
            Creators = db.Creators.ToList(),
            Issue = issue,
        };
        return View(issueEdit);
    }

Я могу вставить Issues, и я могу вставить новый issue.Creators без проблем.Но, когда я пытаюсь удалить текущий issue.Creators, чтобы потом вставить новые, issue.Creators ВСЕГДА равен нулю , поэтому он никогда не обновится до пустого списка.Я не понимаю этого.issue.Creators содержит записи, потому что, когда код переходит к вставке новых создателей, я получаю ошибку, подобную этой:

Violation of PRIMARY KEY constraint 'PK__CreatorI__13D353AB03317E3D'. Cannot insert duplicate key in object 'dbo.CreatorIssues'.
The statement has been terminated. 

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: System.Data.SqlClient.SqlException: Violation of PRIMARY KEY constraint 'PK__CreatorI__13D353AB03317E3D'. Cannot insert duplicate key in object 'dbo.CreatorIssues'.
The statement has been terminated.

Source Error: 


Line 59:    issue.Creators = db.Creators.Where(x => CreatorIds.Contains(x.CreatorId)).ToList();
Line 60:    db.Entry(issue).State = System.Data.EntityState.Modified;
Line 61:    db.SaveChanges();
Line 62:
Line 63:    return RedirectToAction("Index");

Как мне получить issue.Creators, чтобы точно показать текущие отношения, чтобы я могудалить их?

Обновление: рабочий контроллер

    [HttpPost]
    public ActionResult EditIssue ( Issue issue, int[] CreatorIds )
    {
        if(CreatorIds == null)
            ModelState.AddModelError("CreatorIds", "Please specify at least one creator");

        if(ModelState.IsValid)
        {
            // insert or update the issue record (no relationship)
            if (issue.IssueId == 0)
                db.Issues.Add(issue);
            else
                db.Entry(issue).State = System.Data.EntityState.Modified;
            db.SaveChanges();

            // insert and update many to many relationship
            issue = db.Issues.Include("Creators").Where(x => x.IssueId == issue.IssueId).Single();
            issue.Creators = db.Creators.Where(x => CreatorIds.Contains(x.CreatorId)).ToList();
            db.Entry(issue).State = System.Data.EntityState.Modified;
            db.SaveChanges();

            return RedirectToAction("Index");
        }

        IssueEditModel issueEdit = new IssueEditModel{
            Creators = db.Creators.ToList(),
            Issue = issue,
        };
        return View(issueEdit);
    }

Ответы [ 2 ]

1 голос
/ 09 июня 2011

Связыватель модели не загружает их за вас - ваш проблемный объект, появляющийся из вида, не будет волшебным образом содержать их, если вы не настроите все правильно для связывания.

Не видя вашего взгляда, невозможно сказать почему, но достаточно сказать, что вам придется загрузить их, а затем удалить их. Вы можете загрузить новый объект проблем, а затем выполнить TryUpdateModel (проблемы), чтобы обновить значения формы в этой модели. Затем удалите все вопросы. Создатели (если это намеченное действие)


 if(ModelState.IsValid)
 {

   var issueFromDb = db.Issues.Where(x => criteria here);
   bool updateSuccessful = TryUpdateModel(issueFromDb);
   foreach(var creator in issueFromDb.Creators)
   {
     //delete creator if thats what you want
   }




Однако, если вы хотите, чтобы все ваши создатели возвращались со страницы без загрузки, проверьте привязку к перечисляемому. Есть много сообщений об этом, вот один: Привязка модели ASP.NET MVC3 с использованием IEnumerable (Невозможно определить тип из)

Если связь существует, Создатели должны автоматически загружаться только при загрузке Проблемы. Вам не нужно загружать только создателей. Загрузите вашу полную модель, чтобы убедиться, что она работает так же, как и в редактировании выше. Ваш код «должен» работать нормально, но, возможно, вам нужно .Include («Создатели») попробовать это:

var testIssue = from o in db.Issues.Include("Creators") 
where o.IssueId == issue.IssueId 
select o;
foreach(var creator in testIssue.Creators)
{
//check creator
}

это даст вам знать, правильно ли загружается «Создатели».

0 голосов
/ 09 июня 2011

Вам не хватает ключевого тега в классе проблемы (IssueId).

Как только у вас появятся дубликаты, вам может понадобиться зайти в базу данных и вручную удалить строки

...