Я добавил ответ, который решил мою проблему. Надеюсь, это поможет вам понять, что я пытался решить. Спасибо за попытку помочь.

тоящее время у нас есть пакет, который генерирует linq select динамически из полей из строки. Он хорошо работает с плоскими свойствами, но не предназначен для работы с вложенными полями, такими как someObj.NestedObj.SomeField.

Наш текущий код работает как показано ниже в методе обслуживания:

_context.Shipments
    .Where(s => s.Id == request.Id) // it does not matter just an example
    .Select(request.Fields)
    .ToPage(request); // ToPage extension comes from a nuget package

Параметр «fields» объекта запроса - это просто строка, разделенная запятыми, включая свойства объекта Shipment.

Я произвел некоторый рефакторинг в Shipment, я сгруппировал некоторые поля в новый класс с именем Address и добавил его в Shipment, как показано ниже:

// before refactoring
class Shipment {
    // other fields...
    public string SenderAddress;
    public string SenderCityName;
    public string SenderCityId;

    public string RecipientAddress;
    public string CityName;
    public string CityId;
}

// after refactoring
class Shipment {
   // other fields...
   public Address Sender;
   public Address Recipient;
}

class Address {
    public string AddressText;
    public string CityName;
    public string CityId;
}

Ради текущего отображения базы данных я добавил соответствующие отображения как:

public class ShipmentMap : DataEntityTypeConfiguration<Shipment>
    {
        public ShipmentMap()
        {
            ToTable("Shipments");
            // other property mappings
            Property(s => s.Recipient.AddressText).HasMaxLength(1100).HasColumnName("RecipientAddress");
            Property(s => s.Recipient.CityName).HasMaxLength(100).HasColumnName("CityName");
            Property(s => s.Recipient.CityId).IsOptional().HasColumnName("CityId");

            Property(s => s.Sender.AddressText).HasMaxLength(1100).HasColumnName("SenderAddress");
            Property(s => s.Sender.CityName).HasMaxLength(100).HasColumnName("SenderCityName");
            Property(s => s.Sender.CityId).IsOptional().HasColumnName("SenderCityId");
        }
    }

DataEntityTypeConfiguration приходит из пакетов nuget как:

  public abstract class DataEntityTypeConfiguration<T> : EntityTypeConfiguration<T> where T : class
  {
    protected virtual void PostInitialize();
  }

Итак, моя проблема с select (fields) не работает, когда fields = "Recipient.CityId".

Как я могу динамически генерировать linq для выбора с вложенными полями?

Я попробовал ниже, используяLINQ: динамический выбор Но это не работает.

// assume that request.Fields= "Recipient.CityId"

// in the service method
List<Shipment> x = _context.Shipments
    .Where(s => s.Id == request.Id)
    .Select(CreateNewStatement(request.Fields))
    .ToList();


 // I tried to generate select for linq here    
 Func<Shipment, Shipment> CreateNewStatement(string fields)
        {
            // input parameter "o"
            var xParameter = Expression.Parameter( typeof( Shipment ), "o" );

            // new statement "new Data()"
            var xNew = Expression.New( typeof( Shipment ) );

            // create initializers
            var bindings = fields.Split( ',' ).Select( o => o.Trim() )
                .Select(o =>
                {
                    string[] nestedProps = o.Split('.');
                    Expression mbr = xParameter;

                    foreach (var prop in nestedProps)
                        mbr = Expression.PropertyOrField(mbr, prop);

                    // property "Field1"
                    PropertyInfo mi = typeof( Shipment ).GetProperty( ((MemberExpression)mbr).Member.Name );
                    //
                    // original value "o.Field1"
                    var xOriginal = Expression.Property( xParameter, mi );

                    MemberBinding bnd = Expression.Bind( mi, xOriginal );
                    return bnd;
                });

            // initialization "new Data { Field1 = o.Field1, Field2 = o.Field2 }"
            var xInit = Expression.MemberInit( xNew, bindings );

            // expression "o => new Data { Field1 = o.Field1, Field2 = o.Field2 }"
            var lambda = Expression.Lambda<Func<Shipment,Shipment>>( xInit, xParameter );

            // compile to Func<Data, Data>
            return lambda.Compile();
        }

Он выдает исключение, потому что mbr становится CityId после цикла, а "mi" равно нулю, потому что в отгрузке нет поля CityId. Что мне здесь не хватает? Как я могу создать динамический выбор для данной строки с вложенными свойствами?

ОБНОВИТЬ :

Я нашел решение и добавил его в качестве ответа, а также создал Github Gist для решения:

https://gist.github.com/mstrYoda/663789375b0df23e2662a53bebaf2c7c

Ответы на вопрос(1)

Ваш ответ на вопрос