开发者

Linq Union: How to add a literal value to the query?

I need to add a literal value to a query. My attempt

var aa = new List<long>();
aa.Add(0);
var a = Products.Select(p => p.sku).Distinct().Union(aa);

a.ToList().Dump(); // LinqPad's way of showing the values

In the above example, I get an error:

"Local sequence cannot be used in LINQ to SQL implementation
of query operators except the Contains() operator."

If I am using Entity Framework 4 for example, what could I add to the Union statement to always include the "seed" ID?

I am trying to produce SQL code like the following:

select distinct ID
from   product
union
select 0 as ID

So later I can join the list to itself so I can find all values where the next highest value is not present (finding the lowest available ID in the set).

Edit: Original Linq Query to find lowest available ID

var skuQuery = Context.Products
               .Where(p => p.sku > skuSeedStart && 
                           p.开发者_如何学Csku < skuSeedEnd)
               .Select(p => p.sku).Distinct();

var lowestSkuAvailableList = 
    (from p1 in skuQuery
     from p2 in skuQuery.Where(a => a == p1 + 1).DefaultIfEmpty()
     where p2 == 0  // zero is default for long where it would be null
     select p1).ToList();
var Answer = (lowestSkuAvailableList.Count == 0 
              ? skuSeedStart : 
              lowestSkuAvailableList.Min()) + 1;

This code creates two SKU sets offset by one, then selects the SKU where the next highest doesn't exist. Afterward, it selects the minimum of that (lowest SKU where next highest is available).

For this to work, the seed must be in the set joined together.


Your problem is that your query is being turned entirely into a LINQ-to-SQL query, when what you need is a LINQ-to-SQL query with local manipulation on top of it.

The solution is to tell the compiler that you want to use LINQ-to-Objects after processing the query (in other words, change the extension method resolution to look at IEnumerable<T>, not IQueryable<T>). The easiest way to do this is to tack AsEnumerable() onto the end of your query, like so:

var aa = new List<long>();
aa.Add(0);
var a = Products.Select(p => p.sku).Distinct().AsEnumerable().Union(aa);

a.ToList().Dump(); // LinqPad's way of showing the values


Up front: not answering exactly the question you asked, but solving your problem in a different way.

How about this:

var a = Products.Select(p => p.sku).Distinct().ToList();

a.Add(0);

a.Dump(); // LinqPad's way of showing the values


You should create database table for storing constant values and pass query from this table to Union operator.

For example, let's imagine table "Defaults" with fields "Name" and "Value" with only one record ("SKU", 0).

Then you can rewrite your expression like this:

        var zero = context.Defaults.Where(_=>_.Name == "SKU").Select(_=>_.Value);
        var result = context.Products.Select(p => p.sku).Distinct().Union(zero).ToList();
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜