Подзапрос Linq для несвязанной переменной сущности

Можно ли преобразовать/дублировать следующее с помощью Linq?

DECLARE @UserID INT = 1, @ViewerUserID INT = 1002;

SELECT UGR.*,
CASE
WHEN (
    SELECT subR.[Level]
    FROM UserGameRanks subUGR WITH (NOLOCK)
    INNER JOIN Ranks subR WITH (NOLOCK) ON (subUGR.RankId = subR.Id)
    INNER JOIN Games subG WITH (NOLOCK) ON (subUGR.GameId = subG.Id)
    INNER JOIN Users subU WITH (NOLOCK) ON (subUGR.UserID = subU.Id)
    WHERE subUGR.IsDeleted = 0 AND subU.Id = @ViewerUserID AND subUGR.GameID = UGR.GameId
) > R.[Level] THEN 1
ELSE 0
END AS CanEdit
FROM UserGameRanks UGR WITH (NOLOCK)
INNER JOIN Ranks R WITH (NOLOCK) ON (UGR.RankId = R.Id)
INNER JOIN Games G WITH (NOLOCK) ON (UGR.GameId = G.Id)
INNER JOIN Users U WITH (NOLOCK) ON (UGR.UserID = U.Id)
WHERE UGR.IsDeleted = 0 AND U.Id = @UserID
AND
(
    (
        (@ViewerUserID <> - 1)
        AND
        (UGR.VisibilityId = 1)
    )
    OR
    (
        (UGR.VisibilityId = 2)
    )
    OR
    (
        (UGR.VisibilityId = 0)
        AND
        (@UserID = @ViewerUserID)
    )
)

В частности, подзапрос CASE? Я добавил значение [NotMapped] CanEdit в класс сущности Users, однако я не уверен, как заполнить его одним sql-запросом вместо того, чтобы сначала выполнить начальное получение, а затем выполнить цикл и обновить CanEdit.

Я просмотрел StackOverflow.

Любая помощь будет оценена.

РЕДАКТИРОВАТЬ: Глядя на ваши ответы, я вижу, как это сделать, но я понял, что придумал материал в вопросе. Я изначально создал вышеуказанный запрос в качестве примера для моей проблемы, но теперь я вижу, что он не имеет прямого отношения к моей проблеме. Я обновил часть SQL...

Идея состоит в том, что у нас может быть много рангов с самым низким рангом «Не установлен», что будет уровнем 0. Поэтому, если я играю в игру, в которую играет другой пользователь, и мой ранг установлен на уровне 2, я могу назначить ранг этому пользователю. на 1. Но в другой игре я также мог бы быть «не установлен» (уровень 0) и, таким образом, не мог бы редактировать свой ранг.

@CodingYoshi: это то, что я пытался

var viewerQuery = from ugr in context.UserGameRanks
                               join r in context.Ranks on ugr.RankId equals r.Id
                               join g in context.Games on ugr.GameId equals g.Id
                               join u in context.Users on ugr.UserId equals u.Id
                               where (!ugr.IsDeleted) && (ugr.UserId == viewerUserId)
                               select new { UserGameRank = ugr };

            var query = from ugr in context.UserGameRanks
                        join r in context.Ranks on ugr.RankId equals r.Id
                        join g in context.Games on ugr.GameId equals g.Id
                        join u in context.Users on ugr.UserId equals u.Id
                        where (!ugr.IsDeleted) && (ugr.UserId == userId) &&
                        (
                            (viewerUserId != -1 && ugr.VisibilityId == Visibility.RegisteredUsers)
                            ||
                            (ugr.VisibilityId == Visibility.Public)
                            ||
                            (ugr.VisibilityId == Visibility.Hidden && userId == viewerUserId)
                        )
                        select new { GameName = g.Name, Username = ugr.Username, RankName = r.Name, CanEdit = (viewerQuery.Rank.Level > r.Level ? 1 : 0) };

person 0100110101000110    schedule 11.11.2018    source источник
comment
Для части случая используйте тернарный оператор С#, как показано здесь. То, что вы хотите сделать, прямолинейно, вы предпринимали какие-либо попытки?   -  person CodingYoshi    schedule 12.11.2018
comment
Смотрите мое редактирование :3 Я посмотрю на это.   -  person 0100110101000110    schedule 12.11.2018


Ответы (3)


Возможно что-то вроде этого:

var users = new List<User>
{
    new User { Id = 1, UserName = "User1", UserTypeId = 1 }, 
    new User { Id = 2, UserName = "User2", UserTypeId = 2 }, 
    new User { Id = 3, UserName = "User3", UserTypeId = 2 }, 
};

var userTypes = new List<UserType>
{
    new UserType { Id = 1, Type = "Admin", Security = 1 }, 
    new UserType { Id = 2, Type = "User", Security = 2  }
};

var userId = 1;

var ViewerUserID = 2;
var viewerSecurity = 
    (from u in users
    join ut in userTypes on u.UserTypeId equals ut.Id
    where u.Id == ViewerUserID
    select ut.Security).FirstOrDefault();

var res = 
    (from u in users
    join ut in userTypes on u.UserTypeId equals ut.Id
    where u.Id == userId || u.Id == -1
    select new
    {
        Id = u.Id,
        UserName = u.UserName,
        CanEdit = viewerSecurity > ut.Security ? 1 : 0
    });
}

class User {
    public int Id {get; set;}
    public string UserName {get; set;}
    public int UserTypeId {get; set;}
}

class UserType {
    public int Id {get; set;}
    public string Type {get; set;}
    public int Security {get; set;}
}

ОБНОВЛЕНИЕ: Прежде всего, нет необходимости редактировать свой вопрос, потому что другие люди ответили на ваш первоначальный вопрос, и теперь их и мой первоначальный ответ не имеют смысла. Вы должны были начать новый вопрос или обновить этот.

Вот код для вашего отредактированного вопроса:

var res = 
    (from ugr in userGameRanks
    join r in ranks on ugr.RankId equals r.Id
    join g in games on ugr.GameId equals g.Id
    join u in users on ugr.UserId equals u.Id
    where !ugr.IsDeleted    // assuming IsDeleted is of type BIT in your DB
        && u.Id == userId
        && (
                (ViewerUserID != -1 && ugr.VisibilityId == 1)
                || ugr.VisibilityId == 2
                || (ugr.VisibilityId == 0 && userId == ViewerUserID)
            )
    let level =
        (from subUGR in userGameRanks
        join subR in ranks on subUGR.RankId equals subR.Id
        join subG in games on subUGR.GameId equals subG.Id
        join subU in users on subUGR.UserId equals subU.Id
        where !subUGR.IsDeleted 
            && subU.Id == ViewerUserID
            && subUGR.GameId == ugr.GameId
        select subR.Level).FirstOrDefault()

    select new 
    {
        ugr.RankId, 
        ugr.UserId,
        ugr.GameId,
        ugr.IsDeleted,
        ugr.VisibilityId,
        CanEdit = level > r.Level ? 1 : 0
    });

Надеюсь это поможет

person Dmitry Stepanov    schedule 11.11.2018
comment
Ваш ответ заставил меня понять, что мне нужно обновить свой вопрос. - person 0100110101000110; 12.11.2018
comment
Приношу свои извинения, учту это для будущих вопросов. - person 0100110101000110; 12.11.2018

Я смоделировал базу данных как классы, чтобы получить правильный синтаксис. Не уверен, что я все правильно понял, но это близко

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            int UserID = 1;
            int ViewerUserID = 2;

            DataBase db = new DataBase();

            var resutls = (from subU in db.subU
                           join subUt in db.subUT on subU.Id equals subUt.UserTypeID
                           select new { subU = subU, subUt = subUt })
                           .Where(x => ((x.subU.Id == ViewerUserID) && (x.subUt.Security > x.subU.Security)) || x.subU.Id == -1)
                           .ToList();
        }
    }
    public class DataBase
    {
        public List<Users> subU { get; set; }
        public List<UserTypes> subUT { get; set; }

    }
    public class Users
    {
        public int Id { get; set; }
        public int Security { get; set; }
    }
    public class UserTypes
    {
        public int UserTypeID { get; set; }
        public int Security { get; set; }
    }
}
person jdweng    schedule 11.11.2018
comment
Это меня смущает. В вашем присоединении вы присоединяетесь к UserTypes на Users.ID равно UserTypes.UserTypeID ? Таблица Users не имеет значения Security, она хранится только в UserTypes. - person 0100110101000110; 12.11.2018
comment
Я мог ошибиться. Я пытался создать запрос на основе того, что вы опубликовали Select. Я посмотрю на ваши обновления чуть позже сегодня. Я думаю, что мое решение намного проще, чем то, которое вы пытаетесь сделать. Вы можете посмотреть левое внешнее соединение на следующей веб-странице msdn: code.msdn. microsoft.com/101-LINQ-Samples-3fb9811b - person jdweng; 12.11.2018
comment
О, спасибо за ссылку, это будет действительно полезно. - person 0100110101000110; 12.11.2018

Несколько проблем:

1) Что со всеми соединениями? У вас должны быть правильно настроены свойства навигации в конфигурациях вашей модели.

2) Свойство CanEdit вашего результирующего запроса зависит от уровня ранга игры для указанного viewerUserId, но, похоже, указывать viewerUserId необязательно. Каково поведение по умолчанию, если пользователь просмотра не указан или не найден? Я предполагаю, что CanEdit должно быть ложным.

public class YourResultClass()
{
    public string GameName { get; set; }
    public string UserName { get; set; }
    public string RankName { get; set; }
    public bool CanEdit { get; set; }
}

var targetUserGameRanksQuery = context.Users
    .Where(u => !u.IsDeleted 
        && u.UserId == userId)
    // flatten for use in subsequent join
    .SelectMany(u => u.UserGameRanks);

IQueryable<YourResultClass> query = null;

if(viewerUserId.HasValue)
{
    var viewerGameRanksQuery = context.Users
        .Where(u => !u.IsDeleted 
            && u.UserId == viewerUserId)
        // flatten for use in subsequent join
        .SelectMany(u => u.UserGameRanks);

    var joinQuery = targetUserGameRanksQuery // outer source `o`
        .Join(viewerGameRanksQuery, // inner source `i`
            o => o.GameId,
            i => i.GameId,
            (o, i) => new
            {
                GameName = o.Game.Name,
                TargetUserName = o.Username,
                TargetRankName = o.Rank.Name,
                CanEdit = i.Rank.Level > o.Rank.Level,
                Visibility = o.VisibilityId
            });

    query = joinQuery
        .Where(at =>
            at.Visibility == Visibility.RegisteredUsers

            || (at.Visibility == Visibility.Hidden
                && userId == viewerUserId.Value)

            || at.Visibility == Visibility.Public )
        .Select(at =>
            new YourResultClass()
            {
                GameName = at.GameName,
                UserName = at.UserName,
                RankName = at.RankName,
                CanEdit = at.CanEdit,
            });
}
else
{
    query = targetUserGameRanksQuery
        .Where(ugh => ugr.VisibilityId == Visibility.Public)
        .Select(ugh => new YourResultClass()
        {
            GameName = ugr.Game.Name,
            UserName = ugr.Username,
            RankName = ugr.Rank.Name,
            CanEdit = false,
        });
}
person Moho    schedule 12.11.2018