1

Linq と EF の使用

1 つUserは複数持つことができますRoleUserLinks

UserRoleUserLinkテーブルに 2 つのレコードが含まれている場合(1 つはLinkStatusIDofDeletedを持ち、もう 1 つはLinkStatusIDofを持ちAddedます)、以下のクエリは を返しますUser。私はこれをしたくありません。

user関連する が存在する場合に を返さない方法については、以下のケース 3LinkStatusIDAdded参照してください。

IEnumerable<User> z =
    (from users in listOfUsersForReviewer
     join roleUserLinks in context.RoleUserLinks
        on users.UserID equals roleUserLinks.UserID into roleUserLinksJoin
     // left join
     from roleUserLinks in roleUserLinksJoin.DefaultIfEmpty()
     where
         // case 1 - has never been added to a role ie record isn't there
         roleUserLinks.LinkStatus == null
         // case 2 - has been soft deleted from a role so we want this record
         || roleUserLinks.LinkStatusID == (byte)Enums.LinkStatus.Deleted
     select users).Distinct();

ケース 1) ユーザーには関連付けられRoleUserLinkたレコードがありません。ユーザーは期待どおりに返されます

ケース 2) ユーザーには 1 件の関連付けられRoleUserLinkたレコードLinkStatusIDが削除されています。ユーザーは期待どおりに返されます

ケース 3) ユーザーには 2 つの関連付けられRoleUserLinkたレコードがあります。1 件のLinkStatusIDが削除されました。ユーザーを返すべきではありません

4

2 に答える 2

1

私がそれをよく理解していれば、次のようになります。

IEnumerable<User> z =
    (from users in listOfUsersForReviewer
     join roleUserLinks in context.RoleUserLinks
        on users.UserID equals roleUserLinks.UserID into roleUserLinksJoin
     // left join
     from roleUserLinks in roleUserLinksJoin.DefaultIfEmpty()
     where
         (roleUserLinks == null
         || roleUserLinks.LinkStatusID == (byte)Enums.LinkStatus.Deleted)
         && !roleUserLinksJoin.Where(x=> roleUserLinks.LinkStatusID == (byte)Enums.LinkStatus.Added && x.UserID == roleUserLinks.UserID).Any()
     select users).Distinct();

このサブクエリを追加しました:

&& !roleUserLinksJoin.Where(x=> roleUserLinks.LinkStatusID == (byte)Enums.LinkStatus.Added && x.UserID == roleUserLinks.UserID).Any()

RoleUserLinksでレコードを持つユーザーの結果から不要な行を削除しますLinkStatusId Added

また、一致しない場合に備えて回避するためにこれroleUserLinks.LinkStatus == nullを変更しましたroleUserLinks == nullNullReferenceExceptionRoleUserLinkUser

コードをテストしたサンプル コード

static void Main(string[] args)
{
    var usersList = new List<User>()
                    {
                        new User() {UserID = 1},
                        new User() {UserID = 2},
                        new User() {UserID = 3}
                    };

    var userLinksList = new List<RoleUserLink>()
                        {
                            new RoleUserLink() {UserID = 1, State = "del"},
                            new RoleUserLink() {UserID = 2, State = "add"},
                            new RoleUserLink() {UserID = 2, State = "del"}
                        };

    IEnumerable<User> z = (from users in usersList 
                           join roleUserLinks in userLinksList
                           on users.UserID equals roleUserLinks.UserID into roleUserLinksJoin
                           // left join
                           from roleUserLinks in roleUserLinksJoin.DefaultIfEmpty()
                           where
                            // has never been added to a role ie record isn't there
                                roleUserLinks == null
                            // has been soft deleted from a role so we want this record
                                || roleUserLinks.State == "del"
                            // has been added to role so we don't want this record
                                && !roleUserLinksJoin.Where(x=> x.State == "add" && x.UserID == roleUserLinks.UserID).Any()
                            select users).Distinct();
    var res = z.ToList();

}

public class User
{
    public int UserID { get; set; }
}

public class RoleUserLink
{
    public int UserID { get; set; }
    public string State { get; set; }
} 

ID 1 と 3 のユーザーを返します。UserId:1status とのリンクのみがありますdeleteUserId:3にはリンクがありません。またUserId:2、 status とのリンクもあるため、 and は返されませんadd

于 2013-01-08T12:56:19.077 に答える
0

元のクエリを使用してこの問題を解決しました。

IEnumerable<User> z =
    (from users in listOfUsersForReviewer
     join roleUserLinks in context.RoleUserLinks
        on users.UserID equals roleUserLinks.UserID into roleUserLinksJoin
     // left join
     from roleUserLinks in roleUserLinksJoin.DefaultIfEmpty()
     where
         // case 1 - has never been added to a role ie record isn't there
         roleUserLinks.LinkStatus == null
         // case 2 - has been soft deleted from a role so we want this record
         || roleUserLinks.LinkStatusID == (byte)Enums.LinkStatus.Deleted
     select users).Distinct().Include(b => b.RoleUserLinks).ToList();

最後に Include と ToList を追加しました。

それで:

var list = new List<User>();

    foreach (var user in z)
    {
        bool shouldReturnUser = true;
        //get roleLinks
        foreach (var rul in user.RoleUserLinks)
        {
            if (rul.LinkStatusID == (byte) Enums.LinkStatus.Added)
                shouldReturnUser = false;
        }
        if (shouldReturnUser)
            list.Add(user);
    }

次に、このリストを返します。

これを実行してWebサーバーで処理することでパフォーマンスが低下することは理解していますが、これは非常に理解しやすく、機能します:-)

于 2013-01-08T17:21:54.180 に答える