linq to sql пакетное удаление - PullRequest
5 голосов
/ 17 марта 2009

У меня есть следующая БД: Posts, которые имеют Id, Tags также с таблицами Id и TagsToPosts, которые имеют отношения TagsToPosts.PostId => Posts.Id и TagsToPosts.TagId => Tags.Id FK. Мне нужно удалить несколько элементов из TagsToPosts следующим образом. Я создаю IList<Tag> newTags, анализируя строку. У каждого тега есть свое имя. Я хочу удалить все элементы TagsToPosts, указывающие на один пост (TagsToPosts.PostId == mypostid) и указывающие на Tag с именем, которого нет в моем newTags.

Например, у меня есть один пост с Id = 1, тремя тегами: 1 => "tag1", 2 => "tag2", 3 => "tag3" и таблицей связей ManyToMany TagsToPosts: 1 => 1, 1 => 2, 1 => 3 Так что все три тега связаны с моим постом. После этого я создам новый IList<Tag> newList = new List<Tag>(), проанализировав строку. newList содержит: 0 => "tag1", 0 => "tag2". Теперь я хочу удалить третье отношение из таблицы TagsToPosts, потому что мой новый список тегов не содержит тег с именем «tag3». Поэтому мне нужно найти разницу. Я знаю, что могу найти похожие предметы, используя JOIN, но как найти разницу?

Я хочу, чтобы это происходило в одном запросе к БД без итерации по каждому элементу для его удаления.

Ответы [ 4 ]

3 голосов
/ 09 октября 2009

Вы не можете сделать это с LINQ-to-SQL.

LINQ-to-SQL не подходит для пакетных операций - он не может выполнять пакетную вставку, он не может выполнять пакетное обновление и не может выполнять пакетное удаление. Каждый объект в вашей коллекции обрабатывается индивидуально. Все операции можно выполнить за одну транзакцию, но для каждой записи всегда будет запрос.

* MSDN 1006 *

Лучший вариант - написать хранимую процедуру, которая будет делать то, что вы хотите.

0 голосов
/ 18 июня 2015

Мое решение, которое позволяет вам делать удаления, определенные полем класса:

public static void DeleteByPropertyList<T, R>(List<T> listToDelete, Expression<Func<T, R>> getField, DataContext context) where T : class {
    List<List<string>> partitionedDeletes = listToDelete.Select(d => string.Format("'{0}'", getField.Compile()(d).ToString())).ToList().Partition<string>(2000).ToList();
    Func<Expression<Func<T, R>>, string> GetFieldName = propertyLambda => ((MemberExpression)propertyLambda.Body).Member.Name;
    MetaTable metaTable = context.Mapping.GetTable(typeof(T));
    string tableName = string.Format("{0}.{1}", metaTable.Model.DatabaseName, metaTable.TableName);
    foreach (List<string> partitionDelete in partitionedDeletes) {
        string statement = "delete from {0} where {1} in ({2})";
        statement = string.Format(statement, tableName, GetFieldName(getField), string.Join(",", partitionDelete));
        context.ExecuteCommand(statement);
    }
}

public static IEnumerable<List<T>> Partition<T>(this IList<T> source, int size) {
    for (int i = 0; i < Math.Ceiling(source.Count / (double)size); i++)
    yield return new List<T>(source.Skip(size * i).Take(size));
}

Использование:

    List<OrderItem> deletions = new List<OrderItem>();
    // populate deletions
    LinqToSqlHelper.DeleteByPropertyList<OrderItem, long>(deletions, oi => oi.OrderItemId, context);

Он работает только с одним полем, но его можно легко распространить на составные поля.

0 голосов
/ 03 ноября 2009

PLINQO поддерживает операции пакетного удаления без предварительного извлечения объектов.

var delete = from t в TagsToPost выберите t) .Except (из nt в newList выберите nt, новый TagComparer ())

context.Tags.Delete (удаление);

http://plinqo.com

0 голосов
/ 17 марта 2009

Вы смотрели на оператора Linq Except?

Например:

var toDelete = (from t in TagsToPost
                select t).Except(from nt in newList
                                 select nt, new TagComparer());

class TagComparer: IEqualityComparer<TagsToPosts>
{
    public bool Equals(TagsToPosts x, TagsToPosts y)
    {
         return x.Tag.Equals(y.Tag, CompareOptions.Ordinal);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...