代码之家  ›  专栏  ›  技术社区  ›  Major Productions

在MVC2/EF4中很难理解如何处理多对多关系

  •  3
  • Major Productions  · 技术社区  · 14 年前

    我已经写过几次了,但是仍然很难理解如何在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)
    

    当我创建一个新的评论时,我真的只想把条目添加到游戏平台的数据透视表中,因为我只是想把我复习过的游戏链接到已经存在的平台上。在OOP级别处理它让我感到困惑,因为我一直在想我要添加到平台,而我真正想做的是将游戏的id链接到各种平台id。

    所以,我不想从传入的HTTP Post数据创建一个新平台。我只想能够获取表单数据并创建一个新游戏、新的评论内容,并根据选中的复选框将新游戏链接到现有平台。

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

    很抱歉继续喋喋不休地谈论这个问题,但这确实是阻碍我取得重大进展的一个因素。

    1 回复  |  直到 14 年前
        1
  •  1
  •   Nathan Taylor    14 年前

    假设你已经正确地映射了这个实体框架,并且你的游戏对象有一个平台集合,那么将现有的平台分配给一个游戏应该和把这些平台的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() 上面是创建SQL等价物的一个很好的方法 SELECT * FROM TABLE WHERE ID IN(1,2,3,4,5,...) .