【问题标题】:Can't figure out the Logic and Syntax to create this list无法弄清楚创建此列表的逻辑和语法
【发布时间】:2015-09-19 23:12:28
【问题描述】:

鉴于下面的 edmx 文件,我正在尝试编写一个异步 ActionResult,它将为我提供任何用户角色尚未播放的所有场景的列表。我正在尝试找出最有效的方法以及将场景列表放到我的视图中的逻辑。我是 Linq 和 MVC 的新手,所以这很有挑战性。

我目前对 ActionResult 的尝试如下:

    // GET: Home/ChooseScenario
    public async Task<ActionResult> ChooseScenario(string charId)
    {
        //Convert passed in charId string to related Character object 
        var pFSCharacter = await db.PFSCharacters
            .FirstOrDefaultAsync(c => c.PFSCHARACTERID == charId);

        //Initialize empty list of Characters for the User 
        List<PFSCharacter> userCharacters = new List<PFSCharacter>();

        //determine if the pFSCharacter is Core and only give me back a list of characters for the user that are core as well 
        if (pFSCharacter.IsCore)
        {
            userCharacters = await db.PFSCharacters
                .Where(x => x.PFSUSERID == User.Identity.GetUserId() && x.IsCore == true)
                .ToListAsync();
        }
        //If pFSCharacter is not core give me back a list of characters for the user that are not core
        else
        {
            userCharacters = await db.PFSCharacters
                .Where(x => x.PFSUSERID == User.Identity.GetUserId() && x.IsCore == false)
                .ToListAsync();
        }

        List<PFSCharacterScenario> pFSCharacterScenarios = new List<PFSCharacterScenario>();

        //try to figure out the list of Scenarios that none of the User's characters have already participated in
        foreach (PFSCharacter character in userCharacters)
        {
            //can this be done better or in a different way that a foreach loop?
            //can't figure out the logic to give back list of scenarios that each character has not played yet

            //pFSScenarios = await db.PFSCharacterScenarios  //this will overwrite the list need to add to the 
                                                             //list already started for the other characters on 
                                                             //previous loops

            //.ToListAsync();
        }

        //need to remove duplicates scenarios from list so scenario only appears once. 

        //pair down list even further to scenarios that pFSCharacter.charLevel >= pFSScenario.minLevel 
        //and pFSCharacter.charLevel <= pFSScenario.maxLevel


        //var pFSScenarios = db.PFSScenarios
        //    .Include(p => p.PFSFirstSubmittedBy)
        //    .Include(p => p.PFSScenarioType)
        //    .Where(p => p.IsActive == true)

        //    .OrderBy(p => p.PFSSCENARIOTYPEID)
        //    .ThenBy(p => p.Season)
        //    .ThenBy(p => p.SeasonID)
        //    .ThenBy(p => p.MinLevel)
        //    .ThenBy(p => p.ScenarioName);

        //pass pFSCharacter to View to pass to next Controller ActionResult
        ViewBag.Character = pFSCharacter;

        //send list of scenarios to the View to be displayed.
        return View(await pFSScenarios);
    }

编辑:我和朋友一起制定了我需要使用的 SQL 查询。使用 LINQ 将其放入我的控制器的最佳方法是什么?

SELECT *
FROM PFSScenarios
Where PFSSCENARIOID NOT IN (

Select s.PFSSCENARIOID
FROM PFSScenarios s
Inner Join PFSCharacterScenarios cs
    on s.PFSSCENARIOID = cs.PFSSCENARIOID
Inner Join PFSCharacters c
    on c.PFSCHARACTERID = cs.PFSCHARACTERID
WHERE C.PFSUSERID = '35be8bbb-99dc-44bc-9d84-9bcc937d79d6'
)

EDIT3:接近,但仍然出错

Unable to create a constant value of type 'PFSScenarioTracker.Data.EF.PFSCharacter'. Only primitive types or enumeration types are supported in this context.

当使用下面的 Fabio Luz 解决方案时。

如果我使用空白 List&lt;PFSCharacter&gt; userCharacters = new List&lt;PFSCharacter&gt;(); 并注释掉填充 userCharacters 的 if/else statement,错误就会消失,但是它会返回数据库中不符合我添加的其他条件的每个场景 i =&gt; i.IsActive == true &amp;&amp; i.MinLevel &lt;= pFSCharacter.CharLevel &amp;&amp; i.MaxLevel &gt;= pFSCharacter.CharLevel &amp;&amp;

这是我当前的控制器操作结果:

    // GET: Home/ChooseScenario
    public async Task<ActionResult> ChooseScenario(string charId)
    {
        string currentUser = User.Identity.GetUserId();

        //Convert passed in charId string to related Character object 
        var pFSCharacter = await db.PFSCharacters
            .FirstOrDefaultAsync(c => c.PFSCHARACTERID == charId);

        List<PFSCharacter> userCharacters = new List<PFSCharacter>();

        //List<PFSScenario> pFSScenarios = new List<PFSScenario>();
        //determine if the pFSCharacter is Core and only give me back a list of characters for the user that are core as well 
        if (pFSCharacter.IsCore)
        {
            userCharacters = await db.PFSCharacters
                .Where(x => x.PFSUSERID == currentUser && x.IsCore == true)
                .ToListAsync();
        }
        //If pFSCharacter is not core give me back a list of characters for the user that are not core
        else
        {
            userCharacters = await db.PFSCharacters
                .Where(x => x.PFSUSERID == currentUser && x.IsCore == false)
                .ToListAsync();
        }

        var pFSScenarios = await db.PFSScenarios.Where(i => i.IsActive == true && i.MinLevel <= pFSCharacter.CharLevel && i.MaxLevel >= pFSCharacter.CharLevel && !i.PFSCharacterScenarios.Any(x => userCharacters.Contains(x.PFSCharacter))).ToListAsync();

        //pass pFSCharacter to View to pass to next Controller ActionResult
        ViewBag.Character = pFSCharacter;

        //send list of scenarios to the View to be displayed.
        return View(pFSScenarios);
    }

【问题讨论】:

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


    【解决方案1】:

    如果你想得到一个用户角色没有玩过的所有场景的列表:

    //this returns all scenarios that have not been played by any of the Users
    var scenarios = await db.PFSScenarios.Where(i => i.PFSCharacterScenarios.Any()).ToListAsync();
    

    编辑

    //this returns all scenarios that have not been played by any of the User's Chars
    var scenarios = await db.PFSScenarios.Where(i => !i.PFSCharacterScenarios.Any(x => userCharacters.Contains(x.PSFCharacter))).ToListAsync();
    

    我不熟悉你的模型,不确定它是否正确。我想说的是“使用导航属性”,我认为它们会解决您的问题。

    【讨论】:

    • 请避免使用.Count() &lt; 1,而是使用!.Any(),因为前者会迭代整个集合,而后者会在找到第一个项目时停止...
    • 一般来说,当使用 linq 到对象时 Any 几乎总是更快,但是当使用 Linq 到实体 Count() > 0 时可能会更快,这纯粹是因为 EF 生成的经常令人费解的 SQL 跨度>
    • 想要确认 z =&gt;.PFSCHARACTERID 应该是 z =&gt; z.PFSCHARACTERID
    • 刚刚尝试实现这个并得到Exception Details: System.NotSupportedException: Unable to create a constant value of type 'PFSScenarioTracker.Data.EF.PFSCharacter'. Only primitive types or enumeration types are supported in this context.
    • @Fabio 尝试了您的解决方案,但仍然出现错误。我认为这与我上面的 If/Else 语句有关。
    【解决方案2】:

    在@Fabio 的帮助下,我能够为将其用于我的控制器的玩家正确显示列表:

        public async Task<ActionResult> ChooseScenario(string charId)
        {
            string currentUser = User.Identity.GetUserId();
    
            //Convert passed in charId string to related Character object 
            var pFSCharacter = await db.PFSCharacters
                .FirstOrDefaultAsync(c => c.PFSCHARACTERID == charId);
    
            var pFSScenarios = await db.PFSScenarios
                .Where(
                    i => i.IsActive == true &&
                    i.MinLevel <= pFSCharacter.CharLevel && 
                    i.MaxLevel >= pFSCharacter.CharLevel &&
                    !i.PFSCharacterScenarios
                    .Any(
                        x => x.PFSCharacter.IsCore == pFSCharacter.IsCore &&
                        x.PFSCharacter.PFSUser.PFSUSERID == currentUser))
                    .ToListAsync();
    
            //pass pFSCharacter to View to pass to next Controller ActionResult
            ViewBag.Character = pFSCharacter;
    
            //send list of scenarios to the View to be displayed.
            return View(pFSScenarios);
        }
    

    去掉 If/Else 语句并使用 .any 来查找当前登录用户的 USER ID,以查找当前 PFSCharacterScenarios 表中的任何字符。

    【讨论】:

      猜你喜欢
      • 2016-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-17
      • 1970-01-01
      • 2014-02-16
      相关资源
      最近更新 更多