简体   繁体   English

如何同时从两个不同的列中执行OrderBy,而不使用ThenBy

[英]How to perform an OrderBy from two different columns at the same time, not using ThenBy

I have a unique situation where I am trying to do an .OrderBy on an IQueryable. 我有一种独特的情况,我试图在IQueryable上执行.OrderBy。 (Forgive me if my definitions are not accurate) (如果我的定义不正确,请原谅我)

I've got the following: 我有以下几点:

IQueryable<Source> data = e.Sources.Where(element => element.IsActive == true).OrderBy(el => el.SourceEntityKey);
if (sortDesc.SortDirection == ListSortDirection.Ascending)
{                                                                
     data = data.OrderBy(order => order.EntityBase.EntityName);         
}
else 
{                                 
     data = data.OrderByDescending(order => order.EntityBase.EntityName);
}

The problem is, I can't do this because this is not a value that is actually stored in the database, so it is not supported by LINQ to Entities. 问题是,我无法执行此操作,因为这不是实际存储在数据库中的值,因此LINQ to Entities不支持它。 Sources are actually a list of people and companies. 来源实际上是人员和公司的列表。 As a source, they can have a subtype as either a person or company. 作为来源,他们可以具有个人或公司的子类型。 If they are a company, it has its own table to store the company name. 如果它们是公司,则它具有自己的表来存储公司名称。 If it is a person, it has its own table and has two columns to store the first and last name. 如果是人,则它具有自己的表,并且具有两列来存储名字和姓氏。 So, somehow I need a way to order these by their name even though the name is not stored the same way in the database. 因此,尽管名称在数据库中的存储方式不同,但我仍然需要一种按名称排序的方法。 The real values are this: 真正的价值是这样的:

 EntityBase.Person.FirstName
 EntityBase.Person.LastName
 EntityBase.Company.CompanyName

Another problem is that I can't yet enumerate the list as there is more performed after this. 另一个问题是我无法枚举该列表,因为此后还有更多的执行。 So I need a way to have this done before enumerating to a list. 因此,在枚举到列表之前,我需要一种方法来完成此操作。

Thanks for any help 谢谢你的帮助

EDIT: 编辑:

I was trying to simplify to hopefully make things easier... here are my models with the irrelevant trimmed out. 我试图简化以期使事情变得更容易...这是我的模型,其中不相关的部分进行了修剪。

EntityBase: EntityBase:

[MetadataType(typeof(EntityBaseMetaData))]
public partial class EntityBase
{
    [IgnoreDataMember]
    public Person AsPerson
    {
        get
        {
            Person p = new Person();
            try
            {
                p = (Person)this;
            }
            catch
            {
                p = null;
            }
            return p;
        }
    }

    [IgnoreDataMember]
    public Company AsCompany
    {
        get
        {
            Company c = new Company();
            try
            {
                c = (Company)this;
            }
            catch
            {
                c = null;
            }
            return c;
        }
    }                

    [IgnoreDataMember]
    public string EntityName
    {
        get
        {
            string name = "";
            if (this.AsPerson != null)
            {
                name = this.AsPerson.FirstName + " " + this.AsPerson.LastName;
            }
            else if (this.AsCompany != null)
            {
                name = this.AsCompany.CompanyName;
            }

            return name;
        }            
    }        
}

public class EntityBaseMetaData
{
    //[ScaffoldColumn(false)]
    public object EntityBaseKey { get; set; }
}

Person: 人:

[MetadataType(typeof(PersonMetaData))]
    public partial class Person
    {     
    }

    public class PersonMetaData
    {
        [DisplayName("Person ID")]
        public object EntityBaseKey { get; set; }      

        [DisplayName("First Name")]
        public object FirstName { get; set; }

        [DisplayName("Last Name")]
        public object LastName { get; set; }
    }

Company: 公司:

[MetadataType(typeof(CompanyMetaData))]
public partial class Company
{      
}

public class CompanyMetaData
{
    [DisplayName("Company ID")]
    public object EntityBaseKey { get; set; }

    [DisplayName("Company Name")]
    public object CompanyName { get; set; }

}

Source: 资源:

[MetadataType(typeof(SourceMetaData))]
public partial class Source
{    }

public class SourceMetaData
{   
    [DisplayName("Source ID")]
    public object EntityBaseKey { get; set; }
}

Controller action: 控制器动作:

[GridAction(EnableCustomBinding = true)]
public ActionResult Read(GridCommand command)
{
    Entities e = new Entities();            
    IQueryable<Source> data = e.Sources.Where(element => element.IsActive == true).OrderBy(el => el.EntityBaseKey);

    int count = data.Count();

    //Apply Grid Commands
    if (command != null)
    {           
        //Apply data sort
        foreach (SortDescriptor sortDesc in command.SortDescriptors)
        {
            switch (sortDesc.Member)
            {               
                case "SourceName":                                          
                    if (sortDesc.SortDirection == ListSortDirection.Ascending)
                    {                                                                
                        data = data.OrderBy(order => order.EntityBase.EntityName);
                    }
                    else {                                 
                        data = data.OrderByDescending(order => order.EntityBase.EntityName);

                    }
                    break;              
            }
        }

        //Apply paging
        if (command.PageSize > 0)
        {
            data = data.Skip((command.Page - 1) * command.PageSize).Take(command.PageSize);
        }

    }

    List<SourceView> sources = new List<SourceView>();

    foreach (Source s in data.ToList())
    {
        sources.Add(new SourceView
        {
            EntityBaseKey = s.EntityBaseKey,
            SourceName = s.EntityBase.EntityName,           
        });
    }

    return View(new GridModel
    {
        Data = sources,
        Total = count
    });            
}

This is how I would like it to work. 这就是我希望它能工作的方式。 Also, there is a lot more filtering and sorting going on that isn't shown. 此外,还有很多未显示的过滤和排序操作。 The grid command stuff is for a Telerik grid, from the Telerik Extensions for ASP.Net. 网格命令是用于Telerik网格的,它来自于ASP.Net的Telerik扩展。 It would be much easier if we didn't have to do client side binding, but there is too much database information, so performance with server side binding suffers heavily. 如果我们不必进行客户端绑定,但是数据库信息太多,这会容易得多,因此服务器端绑定的性能会受到严重影响。

I really appreciate the help. 我非常感谢您的帮助。

You could try to define a helper type and use union. 您可以尝试定义助手类型并使用并集。 I defined a Customer type with two subtypes: company and person: 我用两个子类型定义了一个Customer类型:company和person:

private static void OrderingTest()
    {
        Database.SetInitializer(new DropCreateDatabaseAlways<Test1Context>());
        var context = new TestContext();

        context.Customers.Add(new Company { Denomination = "A" });
        context.Customers.Add(new Company { Denomination = "C" });
        context.Customers.Add(new Person { LastName = "B" });
        context.Customers.Add(new Person { LastName = "D" });
        context.SaveChanges();

        var a = (from customer in context.Customers.OfType<Company>()
                 select new CustomerInfo { Name = customer.Denomination, Customer = customer }
                )
                .Union
                (from customer in context.Customers.OfType<Person>()
                 select new CustomerInfo { Name = customer.LastName, Customer = customer }
                 );
        var customerInfoList = a.OrderBy(item => item.Name);
        var customers = customerInfoList.ToList().Select(item => item.Customer);
    }

    class CustomerInfo
    {
        public string Name { get; set; }
        public Customer Customer { get; set; }
    }

EDIT: 编辑:

A couple of observations: 一些观察:

-The two properties added are easier if rewritten like this: -如果这样重写,添加的两个属性会更容易:

public Person AsPerson
{
    get
    {
        return this as Person;
    }
}

-remember to remove ToList in the controller at: -记住要删除控制器中的ToList:

case "SourceName":                            
List<Source> sources = data.ToList();

if you want your skip and take to happen on the database. 如果您想跳过并采取对数据库的操作。

and here is my guess: 这是我的猜测:

I still don't get what the Source entity is for but my suggestion is to add a reverse property named Source to EntityBase so that you can replace: 我仍然不了解Source实体的用途,但我的建议是将一个名为Source的反向属性添加到EntityBase中,以便您可以替换:

IQueryable<Source> data = e.Sources.Where(element => element.IsActive == true).OrderBy(el => el.EntityBaseKey);

with: 有:

IQueryable<EntityBase> data = e.Entities.Where(entityBase => entityBase.Source.IsActive).OrderBy(entityBase => entityBase.Source.EntityBaseKey);

Once your collection is a collection of EntityBase you should be able to query with the following: 一旦您的集合是EntityBase的集合,您就可以使用以下查询:

  var entities = (from entity in data.OfType<Company>()
                  select new EntityBaseInfo { Name = entity.CompanyName, EntityBase = entity }
                 )
                 .Union
                 (from entity in data.OfType<Person>()
                  select new EntityBaseInfo { Name = entity.FirstName + " " + entity.LastName, EntityBase = entity }
                 );
  var orderedEntities = entities.OrderBy(item => item.Name).Select(item => item.EntityBase);

Then you can apply skip and take and in the end when you need to create SourceView you can use: 然后,您可以应用跳过和采用,最后在需要创建SourceView时可以使用:

foreach (EntityBase entity in orderedEntities.ToList())
{
    sources.Add(new SourceView
    {
        EntityBaseKey = entity.Source.EntityBaseKey,
        SourceName = entity.EntityName,           
    });
}

I don't quite get what the Source.EntityBaseKey represents 'cause I miss the full code. 我不太了解Source.EntityBaseKey的含义,因为我错过了完整的代码。 I just tried to modify the code posted to be able to use the union. 我只是试图修改发布的代码以能够使用联合。 Hope it's useful. 希望它有用。

How about you do all of the EF LINQ to Entities work and then sort the resulting list by whatever remaining logic you need, like this: 您如何完成所有EF LINQ to Entities的工作,然后根据所需的其余逻辑对结果列表进行排序,如下所示:

list.Sort(item => item.PropertyToSortBy);

And you can call it multiple times to sort by one property, then another, etc. 您可以多次调用它以按一个属性排序,然后按另一个属性排序,依此类推。

Note: The class T in your List<T> must implement IComparable or IComparable<T> for the simple syntax above to work. 注意: List<T>的类T必须实现IComparableIComparable<T>才能使上面的简单语法起作用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM