Метод, который возвращает запрос из запроса в аргументе - PullRequest
0 голосов
/ 03 ноября 2018

Презентация

У меня есть ContactProfileModel класс сущностей с некоторыми свойствами:

  • 1007 * FirstName *
  • LastName
  • Дата рождения и т. Д.

У меня есть другие сущности, у которых есть ContactProfileModel иностранный ключ. Пример: RegistrationModel.Contact.

Потребность

Я хотел бы создать метод со следующей подписью:

public static Expression<Func<TModel, string>> Contact<TModel>(Expression<Func<TModel, ContactProfileModel>> contact)

И используйте это так:

DisplayQuery.Contact<RegistrationModel>(m => m.ContactProfile))

Как эквивалент

m => m.ContactProfile.FirstName + " " + m.ContactProfile.FirstName + " " + m.ContactProfile.BirthDate.ToShortTimeString()

Цель

Цель - вернуть запрос linq, где result является строкой и содержит различную информацию о контакте. Пример: «Джон Доу (10/10/90)»

Примечание

Я обсуждал с некоторыми людьми, которые сказали мне использовать Expression.Call и Expression.Property, но, к сожалению, у меня недостаточно знаний, чтобы правильно их использовать.

Здесь я раскрываю свою проблему без дополнительных подробностей, но у меня есть причины для создания моего метода только таким образом.

Заранее спасибо.

Ответы [ 2 ]

0 голосов
/ 03 ноября 2018

Вот полная рабочая реализация: код запускается и выводит то, что вы ожидаете.

У меня немного не хватает времени, поэтому я оставлю это так. Если вы хотите получить разъяснения, спросите в комментариях, и я сделаю все возможное, чтобы ответить.

public class Program
{
    private static readonly MethodInfo stringConcatMethod = typeof(string).GetMethod("Concat", new[] { typeof(string[]) });
    private static readonly MethodInfo toShortTimeStringMethod = typeof(DateTime).GetMethod("ToShortTimeString");
    private static readonly PropertyInfo firstNameProperty = typeof(ContactProfileModel).GetProperty("FirstName");
    private static readonly PropertyInfo lastNameProperty = typeof(ContactProfileModel).GetProperty("LastName");
    private static readonly PropertyInfo birthDateProperty = typeof(ContactProfileModel).GetProperty("BirthDate");

    public static void Main()
    {
        var result = Contact<RegistrationModel>(x => x.ContactProfile);

        // Test it
        var model = new RegistrationModel()
        {
            ContactProfile = new ContactProfileModel()
            {
                FirstName = "First",
                LastName = "Last",
                BirthDate = DateTime.Now,
            }
        };
        var str = result.Compile()(model);
    }

    public static Expression<Func<TModel, string>> Contact<TModel>(Expression<Func<TModel, ContactProfileModel>> contact)
    {
        // We've been given a LambdaExpression. It's got a single
        // parameter, which is the 'x' above, and its body
        // should be a MemberExpression accessing a property on
        // 'x' (you might want to check this and throw a suitable
        // exception if this isn't the case). We'll grab the
        // body of the LambdaExpression, and use that as the
        // 'm.ContactProfile' expression in your question. 
        // At the end, we'll construct a new LambdaExpression
        // with our body. We need to use the same ParameterExpression
        // given in this LambdaExpression.
        var modelParameter = contact.Parameters[0];
        var propertyAccess = (MemberExpression)contact.Body;

        // <contact>.FirstName
        var firstNameAccess = Expression.Property(propertyAccess, firstNameProperty);
        // <contact>.LastName
        var lastNameAccess = Expression.Property(propertyAccess, lastNameProperty);
        // <contact>.BirthDate
        var birthDateAccess = Expression.Property(propertyAccess, birthDateProperty);
        // <contact>.BirthDate.ToShortTimeString()
        var birthDateShortTimeStringCall = Expression.Call(birthDateAccess, toShortTimeStringMethod);

        // string.Concat(new string[] { <contact>.FirstName, " ", etc }
        var argsArray = Expression.NewArrayInit(typeof(string), new Expression[]
        {
            firstNameAccess,
            Expression.Constant(" "),
            lastNameAccess,
            Expression.Constant(" "),
            birthDateShortTimeStringCall
        });
        var concatCall = Expression.Call(stringConcatMethod, argsArray);

        // Turn it all into a LambdaExpression
        var result = Expression.Lambda<Func<TModel, string>>(concatCall, modelParameter);
        // Note: if you inspect 'result.DebugView' in a debugger at this 
        // point, you'll see a representation of the expression we've built
        // up above, which is useful for figuring out where things have gone
        // wrong.
        return result;
    }
}

public class ContactProfileModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime BirthDate { get; set; }
}

public class RegistrationModel
{
    public ContactProfileModel ContactProfile { get; set; }
}

Возможно, EF не нравится вызов String.Concat - в этом случае вам, возможно, придется вместо этого использовать набор вызовов Expression.Add.

0 голосов
/ 03 ноября 2018

Первый ответ на StackOverflow, так что будьте добры;)

Я пытался решить проблему, но с выражениями нелегко работать. Спасибо canton7 за ответ. Я отредактировал свой ответ, чтобы показать решение, если вы хотите использовать метод .ToString() в выражениях.

public class ContactProfileModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime BirthDate { get; set; }

    public override string ToString()
    {
        return $"{FirstName} {LastName} {BirthDate.ToShortDateString()}";
    }
}

public class RegistrationModel
{
    public ContactProfileModel ContactProfile { get; set; }
}

public class Program
{
    static void Main(string[] args)
    {
        var registration = new RegistrationModel
        {
            ContactProfile = new ContactProfileModel
            {
                FirstName = "John",
                LastName = "Doe",
                BirthDate = DateTime.Now
            }
        };

        var expression = Contact<RegistrationModel>(m => m.ContactProfile);

        Console.WriteLine(expression.Compile()(registration));
        Console.ReadKey();
    }

    public static Expression<Func<TModel, string>> Contact<TModel>(Expression<Func<TModel, ContactProfileModel>> contact)
    {
        var propertyAccess = (MemberExpression)contact.Body;
        var toString = typeof(ContactProfileModel).GetMethod("ToString");
        var toStringValue = Expression.Call(propertyAccess, toString);

        return Expression.Lambda<Func<TModel, string>>(toStringValue, contact.Parameters[0]);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...