tags:

views:

73

answers:

3

Follow up to this question. I have the following code:

string[] names = new[] { "Bob", "bob", "BoB" };
using (MyDataContext dataContext = new MyDataContext())
{
    foreach (var name in names)
    {
        string s = name;
        if (dataContext.Users.SingleOrDefault(u => u.Name.ToUpper() == s.ToUpper()) == null)
            dataContext.Users.InsertOnSubmit(new User { Name = name });
    }

    dataContext.SubmitChanges();
}

...and it inserts all three names ("Bob", "bob" and "BoB"). If this was Linq-to-Objects, it wouldn't.

Can I make it look at the pending changes as well as what's already in the table?

+1  A: 

Why dont you try something like this

foreach (var name in names)
{
    string s = name;
    if (dataContext.Users.SingleOrDefault(u => u.Name.ToUpper() == s.ToUpper()) == null)
    {
        dataContext.Users.InsertOnSubmit(new User { Name = name });
        break;
    }
}
Daniel A. White
Because 'names' might also contain "Alice" and "Chuck". I just left them out for brevity.
Roger Lipscombe
A: 

I am sorry, I don't understand LINQ to SQL as much.

But, when I look at the code, it seems you are telling it to insert all the records at once (similar to a transaction) using SubmitChanges and you are trying to check the existence of it from the DB, when the records are not inserted at all.

EDIT: Try putting the SubmitChanges inside the loop and see that the code will run as per your expectation.

shahkalpesh
Putting SubmitChanges inside the loop would result in extra round-trips to the database. This is undesirable.
Roger Lipscombe
+1  A: 

I don't think that would be possible in general. Imagine you made a query like this:

dataContext.Users.InsertOnSubmit(new User { GroupId = 1 });
var groups = dataContext.Groups.Where(grp => grp.Users.Any());

The database knows nothing about the new user (yet) because the insert wasn't commited yet, so the generated SQL query might not return the Group with Id = 1. The only way the DataContext could take into account the not-yet-submitted insert in cases like this would be to get the whole Groups-Table (and possibly more tables, if they are affected by the query) and perform the query on the client, which is of course undesirable. I guess the L2S designers decided that it would be counterintuitive if some queries took not-yet-committed inserts into account while others wouldn't, so they chose to never take them into account.

Why don't you use something like

foreach (var name in names.Distinct(StringComparer.InvariantCultureIgnoreCase))

to filter out duplicate names before hitting the database?

nikie
I can't use names.Distinct, because names (in my real code) is also a Linq-to-SQL query from another database. But I take your point about the fact that L2S can't do this in the general case.
Roger Lipscombe
@Roger: if you want to enumerate over all the names, you have to get the whole set from the DB anyway, so why not use .ToList() to get them and use .Distinct on the resulting Linq-To-Objects List?
nikie