Asp.net mvc 2 在MVC2/EF4中难以理解如何处理多对多关系

Asp.net mvc 2 在MVC2/EF4中难以理解如何处理多对多关系,asp.net-mvc-2,entity-framework-4,many-to-many,Asp.net Mvc 2,Entity Framework 4,Many To Many,关于这一点我已经写过几次了,但是我仍然很难理解如何在MVC2和EF4中处理多对多关系,特别是在创建和编辑功能时。我认为我的问题的一部分是,我决定以这样一种方式创建数据库表,即透视表在模型本身中不可见 我的桌子,再一次: Games: int GameID (primary key, auto-incr) string GameTitle string ReviewTitle int Score int ReviewContentID (foreign key fro

关于这一点我已经写过几次了,但是我仍然很难理解如何在MVC2和EF4中处理多对多关系,特别是在创建和编辑功能时。我认为我的问题的一部分是,我决定以这样一种方式创建数据库表,即透视表在模型本身中不可见

我的桌子,再一次:

Games:
   int GameID (primary key, auto-incr)
   string GameTitle
   string ReviewTitle
   int Score
   int ReviewContentID (foreign key from Content - News, Articles, and Game reviews all have similar content requirements)
   int GenreID (foreign key from Genres)

Platforms:
   int PlatformID (primary key, auto-incr)
   string Name

GamePlatform (not visible in model):
   int GameID (foreign key from Games)
   int PlatformID (foreign key from Platforms)
当我创建一个新的评论时,我真的只想在GamePlatform透视表中添加条目,因为我只是试图将我评论的游戏链接到现有的平台。在面向对象的层次上处理它让我感到困惑,因为我一直认为我在添加平台,而我真正想做的就是将游戏id链接到各种平台id

因此,我不想从传入的HTTPPOST数据创建新的平台。我只希望能够获取表单数据,创建新游戏、新评论内容,并根据选中的复选框将新游戏链接到现有平台

我了解如何执行前两项任务。这是我似乎无法理解的联系


抱歉继续唠叨这个,但这确实是阻碍我取得重大进展的一件事。

假设您已在实体框架中正确映射此内容,并且您的游戏对象具有平台集合,则将现有平台分配给游戏应该非常简单,只需将这些平台的ID传递给您的游戏添加/编辑操作即可

在表单中,您可以使用一系列复选框,这些复选框的值属性为PlatformID,并使用一个通用名称,例如“platformids”。注意,Html.CheckBox HtmlHelper没有“value”的参数,因此您必须通过htmlAttributes对象来指定它。MVC的默认模型绑定器将通过向接收操作添加匹配参数,自动将表单中的“platformid”值集合分组到单个类型的IEnumerable中

以下是一些让您开始学习的代码:

// games controller

public action AddGame(Game newGame, int[] platformIds) {
    Platforms[] platforms;
    if(platFormIds != null && platformIds.Any()) {
        platforms = ObjectContext.Platforms.Where(ExpressionExtensions.BuildOrExpression<Platform, int>(p => p.PlatformID, platformIds)).ToList();
    }

    if(ModelState.IsValid()) {
        game.Platforms.AddRange(platforms);

        ObjectContext.AddToGames(game);
        ObjectContext.SaveChanges();
    }
}

// helper class 

 public static Expression<Func<TElement, bool>> BuildOrExpression<TElement, TValue>(Expression<Func<TElement, TValue>> valueSelector, IEnumerable<TValue> values) {
    if (valueSelector == null) throw new ArgumentNullException("valueSelector");
    if (values == null) throw new ArgumentNullException("values");

    ParameterExpression p = valueSelector.Parameters.Single();

    if (!values.Any())
        return e => false;

    IEnumerable<Expression> equals = values.Select(value => (Expression)Expression.Equal(valueSelector.Body, Expression.Constant(value, typeof(TValue))));
    Expression body = equals.Aggregate(Expression.Or);

    return Expression.Lambda<Func<TElement, bool>>(body, p);
}

注意:上面的BuildOrExpression只是一种很好的方法,可以创建相当于SELECT*的SQL,从表中,ID为1,2,3,4,5,…。

Wow,不错!有点超出了我目前的C/MVC技能水平,但我想我看到了你的发展方向。对于编辑,是否有可能删除现有链接的方法?比如说我不小心把一款游戏标为DS游戏而不是Wii游戏,我想纠正这个错误。如果有必要,是否有办法删除现有链接?当然,当您创建平台列表以从预检已分配的平台中进行选择时,请使用与上述相同的逻辑。当控制器处理表单时,从游戏对象中清除所有现有平台,并为所有选中的平台创建新平台。我通常处理这个问题的方法是使用while循环:whilegame.Platforms.Any{game.Platforms.Removegame.Platforms.First;}。根据我的经验,调用EntityCollection.Clear会导致集合清空,但实际上不会从数据存储中删除关联的实体。非常感谢!这已经让我发疯好几天了,所以如此突然地接近一个有效的解决方案是难以置信的。再次感谢!