获得IQueryable集之间的差异

时间:2013-10-07 19:08:02

标签: .net sql linq entity-framework

我有一个包含三列的表格。两列组成了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秒钟,它需要几百分之一秒。

3 个答案:

答案 0 :(得分: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;

答案 1 :(得分: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();
}

答案 2 :(得分: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秒钟,它需要几百分之一秒。

  3. 如果其他人有建议,我仍然愿意接受。