2

我有一个三列的表。两列组成PK。该表将有关文件的信息存储在目录中。

我有一个文件目录作为我的输入。

目标是获取已添加文件和已删除文件的列表。

我有以下代码:

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:无法创建“MYProject.ITEM”类型的常量值。此上下文仅支持原始类型或枚举类型。

我认为我的第二个 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 中执行条件语句,而是在 for 循环中的 if 语句中执行。老实说,我认为它很丑陋,但是它有两个好处。

  1. 有用

  2. 不像 LINQ 查询那样需要大约 3 秒,它需要百分之几秒。

4

3 回答 3

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;
于 2013-10-07T19:20:58.643 回答
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 中执行条件语句,而是在 for 循环中的 if 语句中执行。老实说,我认为它很丑陋,但是它有两个好处。

  1. 有用

  2. 不像 LINQ 查询那样需要大约 3 秒,它需要百分之几秒。

但是,如果其他人有建议,我仍然对想法持开放态度。

于 2013-10-10T15:31:07.737 回答
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();
}
于 2013-10-08T00:04:23.257 回答