2

我有一个独特的情况,我试图在 IQueryable 上执行 .OrderBy。(如果我的定义不准确,请原谅我)

我有以下内容:

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);
}

问题是,我不能这样做,因为这不是实际存储在数据库中的值,因此 LINQ to Entities 不支持。来源实际上是人员和公司的列表。作为来源,它们可以具有个人或公司的子类型。如果他们是一家公司,它有自己的表来存储公司名称。如果是人,它有自己的表,并有两列存储名字和姓氏。所以,不知何故,我需要一种方法来按他们的名字对它们进行排序,即使名字在数据库中的存储方式不同。真正的价值是这样的:

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

另一个问题是我还不能枚举列表,因为在此之后还有更多执行。所以我需要一种方法在枚举到列表之前完成这项工作。

谢谢你的帮助

编辑:

我试图简化以希望让事情变得更容易......这是我的模型,其中不相关的修剪掉了。

实体库:

[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; }
}

人:

[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; }
    }

公司:

[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; }

}

来源:

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

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

控制器动作:

[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
    });            
}

这就是我希望它工作的方式。此外,还有更多未显示的过滤和排序正在进行。网格命令的东西用于 Telerik 网格,来自 Telerik Extensions for ASP.Net。如果我们不必进行客户端绑定会容易得多,但是数据库信息太多,因此服务器端绑定的性能会受到很大影响。

我真的很感激帮助。

4

2 回答 2

1

您可以尝试定义一个辅助类型并使用联合。我定义了具有两个子类型的客户类型:公司和个人:

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; }
    }

编辑:

几点观察:

- 如果像这样重写,添加的两个属性会更容易:

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

-记得在控制器中删除 ToList:

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

如果您希望您的跳过并在数据库上发生。

这是我的猜测:

我仍然不明白 Source 实体的用途,但我的建议是向 EntityBase 添加一个名为 Source 的反向属性,以便您可以替换:

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

和:

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

一旦您的集合是 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);

然后你可以应用skip and take,最后当你需要创建SourceView时你可以使用:

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

我不太明白 Source.EntityBaseKey 代表什么,因为我错过了完整的代码。我只是尝试修改发布的代码以便能够使用联合。希望它有用。

于 2013-08-21T00:03:41.850 回答
0

您如何完成所有 EF LINQ to Entities 工作,然后按照您需要的任何剩余逻辑对结果列表进行排序,如下所示:

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

你可以多次调用它来按一个属性排序,然后是另一个,等等。

注意:T你的类List<T>必须实现IComparable或者IComparable<T>上面的简单语法才能工作。

于 2013-08-20T23:36:59.390 回答