Linq to SQL: запросы не смотрят на ожидающие изменения - PullRequest
3 голосов
/ 30 октября 2009

Следите за этим вопросом . У меня есть следующий код:

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();
}

... и он вставляет все три имени ("Bob", "bob" и "BoB"). Если бы это был Linq-to-Objects, он бы не стал.

Могу ли я сделать так, чтобы он посмотрел на ожидающие изменения, а также на то, что уже есть в таблице?

Ответы [ 4 ]

2 голосов
/ 30 октября 2009

Я не думаю, что это было бы вообще возможно. Представьте, что вы сделали запрос, подобный этому:

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

База данных ничего не знает о новом пользователе (пока), потому что вставка еще не зафиксирована, поэтому сгенерированный SQL-запрос может не вернуть Группу с Id = 1. Единственный способ, которым DataContext мог бы принять во внимание не- пока что отправленная вставка в подобных случаях будет заключаться в получении всей таблицы групп (и, возможно, большего числа таблиц, если запрос затрагивает их) и выполнении запроса на клиенте, что, конечно, нежелательно. Я предполагаю, что разработчики L2S решили, что было бы нелогично, если бы некоторые запросы учитывали еще не зафиксированные вставки, а другие - нет, поэтому они решили никогда их не учитывать.

Почему бы вам не использовать что-то вроде

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

чтобы отфильтровать повторяющиеся имена перед попаданием в базу данных?

1 голос
/ 30 октября 2009

Почему бы вам не попробовать что-то подобное

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;
    }
}
0 голосов
/ 19 июня 2014

Вы можете запросить соответствующую коллекцию ChangeSet, например,

if(
    dataContext.Users.
        Union(dataContext.GetChangeSet().Inserts).
        Except(dataContext.GetChangeSet().Deletes).
        SingleOrDefault(u => u.Name.ToUpper() == s.ToUpper()) == null)

Это создаст объединение значений в таблице Users и ожидающих вставках и исключит ожидающие удаления.

Конечно, вы можете захотеть создать переменную changeSet, чтобы предотвратить множественные вызовы функции GetChangeSet, и вам может потребоваться соответствующим образом привести объект в коллекции к соответствующему типу. В коллекциях Inserts and Deletes вы можете захотеть отфильтровать его, например,

...GetChangeSet().Inserts.Where(o => o.GetType() == typeof(User)).OfType<User>()...
0 голосов
/ 30 октября 2009

Извините, я не так хорошо понимаю LINQ to SQL.

Но, когда я смотрю на код, кажется, вы говорите ему вставить все записи сразу (аналогично транзакции), используя SubmitChanges, и вы пытаетесь проверить его наличие в БД, когда записи не вставлены вообще.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...