Prevent sort result of union in entity framework

2019-09-14 20:04发布

问题:

In SQL server union, result is sorted based on primary key column. I want to prevent this behavior in entity framework.
In this post, @praveen has explained how to do this in pure sql. But I want to do this in entity framework.
My code:

public virtual ActionResult Search(string keyword)
{
    var products = _db.Products
        .Where(x => x.IsActive)
        .AsQueryable();

    var productExactlyTitle = products.Where(x => x.Title == keyword);
    var productStartTitle = products.Where(x => x.Title.StartsWith(keyword));
    var productContainsTitle = products.Where(x => x.Title.Contains(keyword)
                                                   || x.Title.Contains(keyword)
                                                   || x.SubTitle.Contains(keyword)
                                                   || x.OtherName.Contains(keyword));


    var productList = productExactlyTitle.Union(productStartTitle)
        .Union(productContainsTitle)
        .Take(10)
        .AsEnumerable()
        .Select(x => new ProductItemViewModel()
        {
            Id = x.Id,
            Title = x.Title,
            Price = x.Price.ToPrice(),
            Image = x.Images.FirstOrDefault(y => y.IsCoverPhoto)?.ImageUrl
        });

        // some code ...        
}

I want to show records with below order:

First: records of productExactlyTitle
Second: records of productStartTitle
Third: records of productContainsTitle

But result is sorted with Id column! and I don't want this.

Is there a way for do this?

回答1:

In SQL all queries without an order by explicitly set is considered unordered. (and EF queries a translated into SQL). So if you want a specific order after your union just specify it.

var result = q1.Union(q2).OrderBy(x => x.?);

For your specific case:

var p1 = productExactlyTitle.Select(x => new { Item = x, Order = 1 });
var p2 = productStartTitle.Select(x => new { Item = x, Order = 2 });
var p3 = productContainsTitle.Select(x => new { Item = x, Order = 3 });
var productList = p1.Union(p2)
                    .Union(p3)
                    .OrderBy(x => x.Order)
                    .Select(x => x.Item)
                    .Take(10);