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 ではサポートされていません。ソースは、実際には人や企業のリストです。ソースとして、個人または会社のサブタイプを持つことができます。会社の場合は、会社名を格納するための独自のテーブルがあります。個人の場合は、独自のテーブルがあり、姓名を格納する 2 つの列があります。そのため、名前がデータベースに同じ方法で保存されていなくても、名前でこれらを注文する方法が必要です。実際の値は次のとおりです。

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

もう1つの問題は、この後にさらに実行されるため、リストをまだ列挙できないことです。したがって、リストに列挙する前にこれを行う方法が必要です。

助けてくれてありがとう

編集:

できれば簡単にするために単純化しようとしていました...これは、無関係なものを取り除いた私のモデルです。

エンティティベース:

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

これが私がそれを機能させたい方法です。また、表示されていないさらに多くのフィルタリングと並べ替えが行われています。grid コマンドは、Telerik Extensions for ASP.Net の Telerik グリッド用です。クライアント側のバインドを行う必要がなければ、はるかに簡単ですが、データベース情報が多すぎるため、サーバー側のバインドのパフォーマンスが大幅に低下します。

本当に助かります。

4

2 に答える 2

1

ヘルパー型を定義してユニオンを使用することができます。company と person の 2 つのサブタイプを持つ Customer タイプを定義しました。

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

編集:

いくつかの観察:

- 追加された 2 つのプロパティは、次のように書き直した方が簡単です。

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

-コントローラーのToListを削除することを忘れないでください:

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

データベースでスキップとテイクを実行したい場合。

ここに私の推測があります:

Source エンティティの目的はまだわかりませんが、Source という名前の逆プロパティを EntityBase に追加して、置き換えることができるようにすることをお勧めします。

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

次に、スキップとテイクを適用し、最後に使用できる 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 に答える