Linq to select data from one table not in other table

I will rewrite it to linq extension methods:

List<string> listString = db.Users.Where(e=>!db.Fi.Select(m=>m.UserID)
                                                  .Contains(e.UserID))
                                  .Select(e=>e.UserName).ToList();

try it, it should work.


First, could you update your question with the entire method so that we can see what might be going on with the ViewBag? Because your code should work just fine, assigning whatever value to the ViewBag is no problem normally:

    ViewBag.property1 = 0;
    ViewBag.property1 = "zero";

works just fine. ViewBag is dynamic. Now, you could get that error if you would later try to assing ViewBag.ddlUserId to something that actually is the wrong type.

I would like you to rewrite your statement as well, let me explain why. Assume for a moment that you have a lot ( > 100.000) of User records in your db.Users and we assume the same for Fi as well. In your code, result1 and result2 are now two lists, one containing >100.000 User objects and the other >100.000 Fi objects. Then these two lists are compared to each other to produce a list of strings. Now imagine the resource required for your web server to process this. Under the assumption that your actually using/accessing a separate SQL server to retrieve your data from, it would be a lot better and faster to let that server do the work, i.e. producing the list of UserID's. For that you'd either use Kirill Bestemyanov's answer or the following:

    var list = (from user in db.Users
                where !db.Fi.Any(f => f.UserID == user.UserID)
                select user.UserName).ToList()

This will produce just one query for the SQL server to execute:

    SELECT 
    [Extent1].[UserName] AS [UserName]
    FROM [dbo].[Users] AS [Extent1]
    WHERE  NOT EXISTS (SELECT 
        1 AS [C1]
    FROM [dbo].[Fi] AS [Extent2]
    WHERE [Extent2].[UserID] = [Extent1].[UserID]
    )}

which in the end is what you want...

Just to clarify more:

    var list = (from user in db.Users
                where !db.Fi.Any(f => f.UserID == user.UserID)
                select user.UserName).ToList()

can be written as the following lambda expression as well:

    var list = db.Users.Where(user => !db.Fi.Any(f => f.UserID == user.UserID))
               .Select(user => user.UserName).ToList()

which from the looks of it is slightly different from Kirill Bestemyanov's answer (which I slightly modified, just to make it look more similar):

    var list = db.Users.Where(user => !db.Fi.Select(f => f.UserID)
                                            .Contains(user.UserID))
                              .Select(user => user.UserName).ToList();

But, they will in fact produce the same SQL Statement, thus the same list.