更新w/ EF4 repo & MVC2的问题无法更新多对多图形。

时间:2022-06-01 19:16:36

I can't seem to successfully update a many-to-many graph in MVC2 using EF4. I figured the simplest thing to do would be to Clear() the entire graph, call SaveChanges(), then rebuild the graph calling SaveChanges() again at the end, but it's not working. All my other properties ARE working, however. First, my Action Methods:

我似乎无法使用EF4成功地更新MVC2中的多对多图。我认为最简单的方法是清除()整个图,调用SaveChanges(),然后在最后重新构建调用SaveChanges()的图形,但它不起作用。但是,我的其他所有属性都在工作。首先,我的操作方法:

    public ActionResult EditReview(int id)
    {
        var game = _gameRepository.GetGame(id);
        var genres = _gameRepository.AllGenres();
        var platforms = _gameRepository.AllPlatforms();

        var model = new AdminGameViewModel { GameData = game, AllGenres = genres, AllPlatforms = platforms }; 

        return View(model);
    }

    //
    // POST: /Admin/EditReview/5

    [HttpPost]
    public ActionResult EditReview([Bind(Prefix="GameData")]Game existingGame, int[] PlatformIDs)
    {
        try
        {
            _gameRepository.ValidateGame(existingGame, PlatformIDs);
        }
        catch(RulesException ex)
        {
            ex.CopyTo(ModelState);
            ex.CopyTo(ModelState, "GameData");
        }

        if (ModelState.IsValid)
        {
            return RedirectToAction("Index");
        }
        else
        {
            var genres = _gameRepository.AllGenres();
            var platforms = _gameRepository.AllPlatforms();

            var model = new AdminGameViewModel { GameData = existingGame, AllGenres = genres, AllPlatforms = platforms };

            return View(model);
        }
    }

The repo itself (ValidateGame and SaveGame are the relevant methods):

repo本身(ValidateGame和SaveGame是相关的方法):

namespace HandiGamer.Domain.Concrete
{
    public class HGGameRepository : IGameRepository
    {
        private HGEntities _siteDB = new HGEntities();

        public List<Game> Games
        {
            get { return _siteDB.Games.ToList(); }
        }

        public void ValidateGame(Game game, int[] PlatformIDs)
        {
            var errors = new RulesException<Game>();

            if (string.IsNullOrEmpty(game.GameTitle))
            {
                errors.ErrorFor(x => x.GameTitle, "A game must have a title");
            }

            if (string.IsNullOrEmpty(game.ReviewText))
            {
                errors.ErrorFor(x => x.ReviewText, "A review must be written");
            }

            if (game.ReviewScore <= 0 || game.ReviewScore > 5)
            {
                errors.ErrorFor(x => x.ReviewScore, "A game must have a review score, and the score must be between 1 and 5");
            }

            if (string.IsNullOrEmpty(game.Pros))
            {
                errors.ErrorFor(x => x.Pros, "Each game review must have a list of pros");
            }

            if (string.IsNullOrEmpty(game.Cons))
            {
                errors.ErrorFor(x => x.Cons, "Each game review must have a list of cons");
            }

            if (PlatformIDs == null || PlatformIDs.Length == 0)
            {
                errors.ErrorForModel("A game must belong to at least one platform");
            }

            if (game.GenreID == 0)
            {
                errors.ErrorFor(x => x.GenreID, "A game must be associated with a genre");
            }

            if (errors.Errors.Any())
            {
                throw errors;
            }
            else
            { 
                SaveGame(game, PlatformIDs);
            }
        }

        public void SaveGame(Game game, int[] PlatformIDs)
        {
            _siteDB.Games.Attach(game);

            if (game.GameID > 0)
            {
                _siteDB.ObjectStateManager.ChangeObjectState(game, System.Data.EntityState.Modified);

                game.Platforms.Clear();
            }
            else
            {
                _siteDB.ObjectStateManager.ChangeObjectState(game, System.Data.EntityState.Added);
            }

            foreach (int id in PlatformIDs)
            {
                Platform plat = _siteDB.Platforms.Single(pl => pl.PlatformID == id);
                game.Platforms.Add(plat);
            }

            game.LastModified = DateTime.Now;

            _siteDB.SaveChanges();
        }

        public Game GetGame(int id)
        {
            return _siteDB.Games.Include("Genre").Include("Platforms").SingleOrDefault(g => g.GameID == id);
        }

        public IEnumerable<Game> GetGame(string title)
        {
            return _siteDB.Games.Include("Genre").Include("Platforms").Where(g => g.GameTitle.StartsWith(title)).AsEnumerable<Game>();
        }

        public List<Game> GetGamesByGenre(int id)
        { 
            return _siteDB.Games.Where(g => g.GenreID == id).ToList();
        }

        public List<Game> GetGamesByGenre(string genre)
        {
            return _siteDB.Games.Where(g => g.Genre.Name == genre).ToList();
        }

        public List<Game> GetGamesByPlatform(int id)
        {
            return _siteDB.Games.Where(g => g.Platforms.Any(p => p.PlatformID == id)).ToList();
        }

        public List<Game> GetGamesByPlatform(string platform)
        {
            return _siteDB.Games.Where(g => g.Platforms.Any(p => p.Name == platform)).ToList();
        }

        public List<Genre> AllGenres()
        {
            return _siteDB.Genres.OrderBy(g => g.Name).ToList();
        }

        public List<Platform> AllPlatforms()
        { 
            return _siteDB.Platforms.OrderBy(p => p.PlatformID).ToList();
        }
    }
}

I'm stumped.

我难住了。

1 个解决方案

#1


1  

Kevin, oh this is a little complex and forces you back to EFv1 patterns because with M:M you don't have foreign keys to lean on and you are stuck with having objects.

Kevin,这有点复杂,你可以回到EFv1模式,因为M:M,你没有外键可以依靠,你被困在有物体的地方。

WHen you add a game, you do want the relationship (i.e. a row in the join table) to be added but you don't want the platform to be added since it's just a reference.

当您添加一个游戏时,您确实需要添加关系(即连接表中的一行),但您不希望添加该平台,因为它只是一个引用。

I haven't actually done this but I think it would be easier if you could break it apart and then rebuild the platforms collection once the game is attached and marked added. Otherwise if you add the whole graph, everything gets marked added.

实际上我还没有这样做,但是我认为如果你能把它拆开,然后在游戏被附加和标记后重建平台集合,那将会更容易。否则,如果你添加整个图形,所有的东西都会被标记。

Problem with EF is that if you attach game you will get the related stuff attached too. There might be a cleaner pattern but my thought is to detach the platforms from the game, attach the game to the context, mark it as added. Then I would attach the platforms to the context. They will be "unchanged". Then add them to the games.platform collection. The platforms will still be unchanged but the : will be understood.

EF的问题是,如果你附加游戏,你会得到相关的东西。可能会有一个更清晰的模式,但我的想法是将游戏平台从游戏中分离出来,将游戏附加到上下文,标记为添加。然后,我将把平台附加到上下文。他们将“不变”。然后把它们添加到游戏中。平台集合。这些平台仍将保持不变,但将被理解。

You may have tried that. I'd have to do it myself and watch the entity state of everything as I go along to see for sure what's happening. The key is that EF needs to track that a relationship has been added and that's new (and will result in a row in the join table being added) but understand that Platforms are not new.

你可能已经试过了。我必须自己去做,并观察所有的实体状态,然后我去看看到底发生了什么。关键是,EF需要跟踪已添加的关系,这是新的(并将导致添加的联接表中的一行),但要理解平台不是新的。

hth julie

hth朱莉

#1


1  

Kevin, oh this is a little complex and forces you back to EFv1 patterns because with M:M you don't have foreign keys to lean on and you are stuck with having objects.

Kevin,这有点复杂,你可以回到EFv1模式,因为M:M,你没有外键可以依靠,你被困在有物体的地方。

WHen you add a game, you do want the relationship (i.e. a row in the join table) to be added but you don't want the platform to be added since it's just a reference.

当您添加一个游戏时,您确实需要添加关系(即连接表中的一行),但您不希望添加该平台,因为它只是一个引用。

I haven't actually done this but I think it would be easier if you could break it apart and then rebuild the platforms collection once the game is attached and marked added. Otherwise if you add the whole graph, everything gets marked added.

实际上我还没有这样做,但是我认为如果你能把它拆开,然后在游戏被附加和标记后重建平台集合,那将会更容易。否则,如果你添加整个图形,所有的东西都会被标记。

Problem with EF is that if you attach game you will get the related stuff attached too. There might be a cleaner pattern but my thought is to detach the platforms from the game, attach the game to the context, mark it as added. Then I would attach the platforms to the context. They will be "unchanged". Then add them to the games.platform collection. The platforms will still be unchanged but the : will be understood.

EF的问题是,如果你附加游戏,你会得到相关的东西。可能会有一个更清晰的模式,但我的想法是将游戏平台从游戏中分离出来,将游戏附加到上下文,标记为添加。然后,我将把平台附加到上下文。他们将“不变”。然后把它们添加到游戏中。平台集合。这些平台仍将保持不变,但将被理解。

You may have tried that. I'd have to do it myself and watch the entity state of everything as I go along to see for sure what's happening. The key is that EF needs to track that a relationship has been added and that's new (and will result in a row in the join table being added) but understand that Platforms are not new.

你可能已经试过了。我必须自己去做,并观察所有的实体状态,然后我去看看到底发生了什么。关键是,EF需要跟踪已添加的关系,这是新的(并将导致添加的联接表中的一行),但要理解平台不是新的。

hth julie

hth朱莉