Converting ESQL to LINQ to Entities. Sort by relat

2019-05-06 14:33发布

I am using EF + RIA and unfortunately meet some problems with sorting by related entities. For such purpose there is ESQL query that I implemented (found only this solution):

var queryESQL = string.Format(
@" select VALUE ent from SomeEntities as ent 
   join Attributes as ea ON ea.EntityId = ent.Id 
   where ea.AttributeTypeId = @typeId
   order by ea.{0} {1}", columnName, descending ? "desc" : "asc");

var query = ObjectContext.CreateQuery<SomeEntity>(queryESQL, new ObjectParameter("typeId", attributeTypeId));                                                        

Tables have following structure:

<Attribute>:
    int Id;
    decimal DecimalColumn;
    string StringColumn;
    int EntityId;
    int AttributeTypeId;

<SomeEntity>:
    int Id;
    string Name;  

Is there any way to rewrite this stuff(sorting), using LINQ to Entities approach?

1条回答
唯我独甜
2楼-- · 2019-05-06 14:46

Here's my attempt, I can't guarantee it will work. I need to think more on how to get a dynamic column name, I'm not sure on that one. EDIT: you can use a string for the order column.

int typeId = 1115;
bool orderAscending = false;
string columnName = "StringColumn";
var query = from ent in SomeEntities
join ea in Attributes on ea.EntityId = ent.Id
where ea.AttributeTypeId = typeId;

if(orderAscending)
{
  query = query.OrderBy(ea => columnName).Select(ea => ea.Value);
}
else
{
  query = query.OrderByDescending(ea => columnName).Select(ea => ea.Value);
}

var results = query.ToList(); // call toList or enumerate to execute the query, since LINQ has deferred execution.

EDIT: I think that ordering after the select stops is from ordering by. I moved the select statement to after the order by. I also added the "query =", but I'm not sure if that is needed. I don't have a way to test this at the moment.

EDIT 3: I fired up LINQPad today and made a few tweaks to what I had before. I modeled your data in a Code-first approach to using EF and it should be close to what you have. This approach works better if you're just trying to get a list of Attributes (which you aren't). To get around that I added an Entity property to the MyAttribute class. This code works in LINQPAD.

void Main()
{
    // add test entities as needed. I'm assuming you have an Attibutes collection on your Entity based on your tables.
    List<MyEntity> SomeEntities = new List<MyEntity>();
    MyEntity e1 = new MyEntity();
    MyAttribute a1 =  new MyAttribute(){ StringColumn="One", DecimalColumn=25.6M, Id=1, EntityId=1, AttributeTypeId = 1, Entity=e1 };
    e1.Attributes.Add(a1);
    e1.Id = 1;
    e1.Name= "E1";
    SomeEntities.Add(e1);

    MyEntity e2 = new MyEntity();
    MyAttribute a2 = new MyAttribute(){ StringColumn="Two", DecimalColumn=198.7M, Id=2, EntityId=2, AttributeTypeId = 1, Entity=e2 };
    e2.Attributes.Add(a2);
    e2.Id = 2;
    e2.Name = "E2";
    SomeEntities.Add(e2);

    MyEntity e3 = new MyEntity();
    MyAttribute a3 = new MyAttribute(){ StringColumn="Three", DecimalColumn=65.9M, Id=3, EntityId=3, AttributeTypeId = 1, Entity=e3 };
    e3.Attributes.Add(a3);
    e3.Id = 3;
    e3.Name = "E3";
    SomeEntities.Add(e3);

    List<MyAttribute> attributes = new List<MyAttribute>();
    attributes.Add(a1);
    attributes.Add(a2);
    attributes.Add(a3);

    int typeId = 1;
    bool orderAscending = true;
    string columnName = "StringColumn";
    var query = (from ent in SomeEntities
    where ent.Attributes.Any(a => a.AttributeTypeId == typeId)
    select ent.Attributes).SelectMany(a => a).AsQueryable();
    query.Dump("Pre Ordering");
    if(orderAscending)
    {
      // query =  is needed
      query = query.OrderBy(att => MyEntity.GetPropertyValue(att, columnName));
    }
    else
    {
      query = query.OrderByDescending(att => MyEntity.GetPropertyValue(att, columnName));
    }

    // returns a list of MyAttributes. If you need to get a list of attributes, add a MyEntity property to the MyAttribute class and populate it
    var results = query.Select(att => att.Entity).ToList().Dump();
}

// Define other methods and classes here
}
    class MyAttribute
    {
    public int Id { get; set; }
    public decimal DecimalColumn { get; set; }
    public string StringColumn { get; set; }
    public int EntityId { get; set; }
    public int AttributeTypeId { get; set; }
    // having this property will require an Include in EF to return it then query, which is less effecient than the original ObjectQuery< for the question
    public MyEntity Entity { get; set; }

    }
    class MyEntity
    {
    public int Id { get; set; }
    public string Name { get; set; }
    public ICollection<MyAttribute> Attributes { get; set; }
    public MyEntity()
    {
    this.Attributes = new List<MyAttribute>();
    }

    // this could have been on any class, I stuck it here for ease of use in LINQPad
    // caution reflection may be slow
    public static object GetPropertyValue(object obj, string property)
{
// from Kjetil Watnedal on http://stackoverflow.com/questions/41244/dynamic-linq-orderby
    System.Reflection.PropertyInfo propertyInfo=obj.GetType().GetProperty(property);
    return propertyInfo.GetValue(obj, null);
}
查看更多
登录 后发表回答