2013-10-07 17 views
2

У меня есть таблица с тремя столбцами. PK. В таблице хранится информация о файлах в каталоге.получить разницу между наборами IQueryable

У меня есть каталог файлов в качестве моего ввода.

Целью является получение списка файлов, которые были добавлены, и тех, которые удалены.

У меня есть следующий код:

string uri = "ftp://ftp.myftpsite.com/files"; 
FtpWebRequest ftpRequest = (FtpWebRequest)WebRequest.Create(uri); 
ftpRequest.Method = WebRequestMethods.Ftp.ListDirectory; 
FtpWebResponse response = (FtpWebResponse)ftpRequest.GetResponse(); 
StreamReader streamReader = new StreamReader(response.GetResponseStream()); 
using (myEntities context = new myEntities()) 
{ 
    IQueryable<ITEM> storedItems = from item in context.ITEMs where item.YEAR == "2013" select item; 
    List<ITEM> currentItemList = new List<ITEM>(); 

    string line = streamReader.ReadLine(); 
    while (!string.IsNullOrEmpty(line) && line.EndsWith(".htm")) 
    { 
     ITEM item = new ITEM(); 
     item.YEAR = line.Substring(0,4); 
     item.NUM = line.Substring(7,5); 
     currentItemList.Add(item);     
     line = streamReader.ReadLine(); 
    } 

    IQueryable<ITEM> currentItems = currentItemList.AsQueryable<ITEM>(); 

    IQueryable<ITEM> newItems = from item in currentItems where !(from storedItem in storedItems select storedItem.YEAR + storedItem.NUM).Contains(item.YEAR + item.NUM) select item; 
    IQueryable<ITEMS> removedItems = from item in storedItems where !(from currentItem in currentItems select currentItem.YEAR + currentItem.NUM).Contains(item.YEAR + item.NUM) select item; 
    List<ITEM> newItemsList = newItems.ToList(); 
    List<ITEM> removedItemsList = removedItems.ToList(); 
} 

В конце newItems должны быть элементы на сайте FTP, а не базы данных и removedItems должны быть элементы в базе данных, а не на сайте FTP.

В newItems работает, но следующая строка возвращает ошибку: List<ITEM> removedItemsList = removedItems.ToList();

Ошибка является:

System.NotSupportedException: Unable to create a constant value of type 'MYProject.ITEM'. Only primitive types or enumeration types are supported in this context.

Что-то не так с моей второй LINQ запрос, я думаю, но я не уверен, какие.

Кроме того, производительность важна, поэтому предложения по эффективности приветствуются.

Текущее решение:

List<string> criteria = (from item in currentItemList select item.YEAR + item.NUM).ToList(); 
foreach(AMENDMENT a in storedItems) 
{ 
    if(!criteria.Contains(a.YEAR + a.NUM)) 
     //do stuff here 
} 

Так в основном, вместо того, чтобы делать условное заявление, в LINQ я сделал это в заявлении, если в цикле. Я честно считаю, что это довольно уродливо, однако у него есть две выгоды.

  1. Он работает

  2. Вместо Ф.О. принимать около 3 секунд, как запросы LINQ были, это занимает несколько сотых долей секунды.

+0

Я отредактировал ваше название. Пожалуйста, смотрите: «Если вопросы включают« теги »в их названиях?] (Http://meta.stackexchange.com/questions/19190/), где консенсус« нет, они не должны ». –

+0

Почему он работает для запроса newItems, а не запроса removeItems? Это по сути тот же запрос? – kralco626

ответ

1

Вы попробовали дизайн? Если ваш размер данных не слишком экстремальный, он не убьет вас. В противном случае вам нужно будет проявить больше творчества.

IQueryable<ITEMS> removedItems = from item in storedItems.ToList() where !(from currentItem in currentItems select currentItem.YEAR + currentItem.NUM).Contains(item.YEAR + item.NUM) select item; 

Ваш запрос нечетный. Другой способ может работать, но я не проверил его. Вы уже подключились к 2013 году, так что это просто так.

List<int> itemNumbers = currentItems.Where(x=>x.YEAR ==2013).Select(x=>x.NUM).ToList(); 
IQueryable<ITEMS> removedItems = from item in storedItems where !itemNumbers.Contains(item.NUM) select item; 
+0

Единственное отличие, которое я вижу в вашем ответе, это то, что вы добавили 'ToList()' в объект storedItems в запросе LINQ. Выполнение этого дает мне ошибку: «Невозможно неявно преобразовать тип« System.Collections.Generic.IEnumerable »в« System.Linq.IQueryable ». Явное преобразование существует (вам не хватает роли?) 'Есть ли что-то в вашем ответе, которое я пропускаю? – kralco626

+0

Я думаю, что второй ответ мог бы работать, но только потому, что теперь он ограничен одним полем, с которым мы проверяем. Я предпочел бы иметь решение, у которого не было этого ограничения. Например, если меня беспокоило не только о 2013 году. – kralco626

+0

ОК, я могу просто сказать 'LIST itemIds = from x in currentItems выбрать x.YEAR + x.NUM', а затем использовать фрагмент:'! ItemIds.Contains (item.YEAR + item.NUM) 'поэтому ваше решение будет работать для использования нескольких полей для сравнения. – kralco626

0

попробовать что-то вроде этого:

using (myEntities context = new myEntities()) 
{ 
    List<ITEM> storedItems = (
     from item in context.ITEMs 
     where item.YEAR == "2013" 
     select item).ToList(); 

    List<ITEM> currentItemList = new List<ITEM>(); 

    string line = streamReader.ReadLine(); 
    while (!string.IsNullOrEmpty(line) && line.EndsWith(".htm")) 
    { 
     ITEM item = new ITEM(); 
     item.YEAR = line.Substring(0,4); 
     item.NUM = line.Substring(7,5); 
     currentItemList.Add(item);     
     line = streamReader.ReadLine(); 
    } 

    List<ITEM> newItemsList = (
     from cItem in currentItems 
     join sItem in storedItems 
      on (cItem.YEAR + cItem.NUM) equals (sItem.YEAR + sItem.NUM) 
      into g 
     from gItem in g.DefaultIfEmpty() 
     where gItem == null 
     select cItem).ToList(); 

    List<ITEM> removedItemsList = (
     from sItem in storedItems 
     join cItem in currentItems 
      on (sItem.YEAR + sItem.NUM) equals (cItem.YEAR + cItem.NUM) 
      into g 
     from gItem in g.DefaultIfEmpty() 
     where gItem == null 
     select sItem).ToList(); 
} 
+0

Будет ли 'on (sItem.YEAR + sItem.NUM) равно (cItem.YEAR + cITEM.NUM)' быть таким же, как 'on sItem.YEAR равно cItem.YEAR && sIteam.NUM равно cItem.NUM' или я что-то упускаю? – kralco626

+0

У меня ничего не было. LINQ ненавидит нас и не позволит нам присоединиться к двум полям lol :) – kralco626

0

Текущее решение:

List<string> criteria = (from item in currentItemList select item.YEAR + item.NUM).ToList(); 
foreach(AMENDMENT a in storedItems) 
{ 
    if(!criteria.Contains(a.YEAR + a.NUM)) 
     //do stuff here 
} 

Так в основном, вместо того, чтобы делать условное заявление, в LINQ я сделал это в, если заявление в для цикла. Я честно считаю, что это довольно уродливо, однако у него есть две выгоды.

  1. Он работает

  2. Вместо Ф.О. принимать около 3 секунд, как запросы LINQ были, это занимает несколько сотых долей секунды.

Если у кого-то есть предложения, я все же открыт для идей.

Смежные вопросы