2013-10-07 85 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做條件語句我做到了if語句在for循環中。我真的認爲它很醜,但它有兩個好處。

  1. 它的工作原理

  2. 相反FO以3秒左右,如LINQ查詢是,它需要一秒鐘的百分之幾。

+0

我編輯了你的標題。請參閱:「[應該在其標題中包含」標籤「](http://meta.stackexchange.com/questions/19190/)」,其中的共識是「不,他們不應該」。 –

+0

爲什麼它對newItems查詢而不是removedItems查詢起作用?他們本質上是相同的查詢? – 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

我在你的答案中唯一的區別是你在LINQ查詢中添加了'ToList()'到storedItems對象。這樣做會給我錯誤:'不能隱式地將類型'System.Collections.Generic.IEnumerable '轉換爲'System.Linq.IQueryable '。存在明確的轉換(你是否缺少演員?)「有什麼關於我缺少的答案? – kralco626

+0

我認爲第二個答案可以工作,但只是因爲它現在只限於我們正在檢查的一個領域。我寧願有一個沒有這個限制的解決方案。例如,如果我不只關心2013. – kralco626

+0

好的,我可以說'LIST itemIds =從currentItems中的x選擇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)'與'sItem.YEAR相同等於cItem.YEAR && sIteam.NUM等於cItem.NUM'還是我錯過了什麼? – kralco626

+0

Aparently我錯過了一些東西。 LINQ恨我們,不會讓我們加入兩個領域大聲笑:) – 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做條件語句我做到了if語句中for循環。我真的認爲它很醜,但它有兩個好處。

  1. 它的工作原理

  2. 相反FO以3秒左右,如LINQ查詢是,它需要一秒鐘的百分之幾。

如果其他人有建議,但我仍然對想法持開放態度。