【问题标题】:Use method for child property in entity framework query实体框架查询中子属性的使用方法
【发布时间】:2013-11-27 22:00:00
【问题描述】:

我能够使用下面帖子中的实体框架方法。

Use method in entity framework query

但是我怎样才能对内部属性使用表达式呢?下面的代码尝试获取健身房列表,但我想通过与事件目录相同的表达式过滤这些健身房。这次我想将它应用到 EventGym 的子属性 Event。 EventGym.Event 属性。

EventGym.cs

[Table("EventGym", Schema = "GrassrootsHoops")]
public class EventGym : BaseEntity
{
    public int EventId { get; set; }

    [ForeignKey("EventId")]
    public virtual Event Event { get; set; }
}

去健身房

public List<MobileVenueModel> GetGyms(string applicationId)
{
    return (from e in _eventsRepository.DataContext.EventGyms
            //where GetEvent(applicationId)
            select new MobileVenueModel
                {
                    Id = e.Id
                }).ToList();
}

public Expression<Func<Event, bool>> GetEvent(string applicationId)
{
    return q => q.Active && q.Visible && q.MobileEventApplications.Any(m =>
                          m.MobileApplication.ApplicationId == applicationId &&
                          (!m.MobileApplication.ActivationLength.HasValue || DbFunctions.AddDays(DateTime.Now, 1) < DbFunctions.AddMonths(m.MobileApplication.DateActivated, m.MobileApplication.ActivationLength.Value)));
}

【问题讨论】:

    标签: c# linq entity-framework entity-framework-6


    【解决方案1】:

    动态构建所有表达式:

    public static Expression<Func<Event,bool>> GetEvent( string applicationId )
    {
        var arg = Expression.Parameter( typeof( Event ), "e" );
    
        return ( Expression<Func<Event, bool>> )Expression.Lambda( GetEvent( arg, applicationId ), arg );
    }
    
    public static Expression<Func<EventGym, bool>> GetEventGymPredicateExpression( string applicationId )
    {
        var arg = Expression.Parameter( typeof( EventGym ), "eg" );
    
        var propSelector = Expression.Property( arg, "Event" );
    
        var existingExp = GetEvent( propSelector, applicationId );
    
        return ( Expression<Func<EventGym, bool>> )Expression.Lambda( existingExp, arg );
    }
    
    public static Expression GetEvent( Expression arg, string applicationId )
    {
        // q.Active
        var activeProp = Expression.Property( arg, "Active" );
    
        // q.Visible
        var visibleProp = Expression.Property( arg, "Visible" );
    
        // q.Active && q.Visible
        var and0 = Expression.AndAlso( activeProp, visibleProp );
    
        var meaProp = arg.Type.GetProperty( "MobileEventApplications" );
        var colType = meaProp.PropertyType;
        var entityType = colType.GetGenericArguments().Single();
    
        var mArg = Expression.Parameter( entityType, "m" );
    
        // m.MobileApplication
        var maProp = Expression.Property( mArg, "MobileApplication" );
        // m.MobileApplication.ApplicationId
        var appIdProp = Expression.Property( maProp, "ApplicationId" );
        // m.MobileApplication.ApplicationId == applicationId
        var appIdEqual = Expression.Equal( appIdProp, Expression.Constant( applicationId ) );
    
        // m.MobileApplication.ActivationLength
        var alProp = Expression.Property( maProp, "ActivationLength" );
        // m.MobileApplication.ActivationLength.HasValue
        var hvProp = Expression.Property( alProp, "HasValue" );
        // !m.MobileApplication.ActivationLength.HasValue
        var notHasValue = Expression.Not( hvProp );
    
        // DbFunctions.AddDays( DateTime.Now, 1 )
        var addDaysFunc = typeof( DbFunctions ).GetMethods().Single( mi => 
            mi.Name == "AddDays" && 
            mi.GetParameters().First().ParameterType == typeof( DateTime? ) );
    
        var nowPlus1d = Expression.Call( null, addDaysFunc, Expression.Constant( DateTime.Now, typeof( DateTime? ) ), Expression.Constant( 1, typeof( int? ) ) );
    
        // m.MobileApplication.DateActivated
        var daProp = Expression.Property( maProp, "DateActivated" );
        // m.MobileApplication.ActivationLength.Value
        var alvProp = Expression.Property( alProp, "Value" );
        // DbFunctions.AddMonths( DateActivated, ActivationLength.Value )
        var addMonthsFunc = typeof( DbFunctions ).GetMethods().Single( mi => 
            mi.Name == "AddMonths" &&
            mi.GetParameters().First().ParameterType == typeof( DateTime? ) );
    
        var addMonths = Expression.Call( null, addMonthsFunc, Expression.Convert( daProp, typeof( DateTime? ) ), Expression.Convert( alvProp, typeof( int? ) ) );
    
        // AddDays < AddMonths
        var ltOp = Expression.LessThan( nowPlus1d, addMonths );
    
        // !HasValue || ( AddDays < AddMonths )
        var orOp = Expression.Or( notHasValue, ltOp );
    
        // AppId == applicationId && ( !HasValue || ( AddDays < AddMonths ) )
        var anyBody = Expression.AndAlso( appIdEqual, orOp );
    
        var anyPredicate = Expression.Lambda( anyBody, mArg );
    
        // q.MobileEventApplications
        Expression meaExp = Expression.Property( arg, meaProp );
    
        var anyMethod = typeof( Queryable ).GetMethods()
            .Single( mi => 
                mi.Name == "Any" && 
                mi.GetParameters().Count() == 2 )
            .MakeGenericMethod( entityType );
    
        // q.MobileEventApplications.Any( m => anyBody )
        var anyCallExp = Expression.Call( null, anyMethod, Expression.Convert( meaExp, typeof( IQueryable<MobileEventApplication> ) ), anyPredicate );
    
        return Expression.AndAlso( and0, anyCallExp );
    
        //return q => q.Active && q.Visible && q.MobileEventApplications.Any(m =>
        //    m.MobileApplication.ApplicationId == applicationId &&
        //    (
        //        !m.MobileApplication.ActivationLength.HasValue || 
        //        DbFunctions.AddDays(DateTime.Now, 1) < DbFunctions.AddMonths(m.MobileApplication.DateActivated, m.MobileApplication.ActivationLength.Value ) ) );
    
    }
    

    【讨论】:

    • 是的,但我怎样才能重复使用我的原件。否则我将不得不有两个功能做同样的事情。
    • 更新 - 编译并调用 GetEvent(string) 传入 EventGym.Event
    • LINQ to Entities 无法识别方法 'Boolean Invoke(Tournaments.Data.Entities.Event)' 方法,并且此方法无法转换为商店表达式。
    • 我也在使用 LinqKit,但不确定我是否也可以使用它
    • 您需要动态构建表达式。我想通了,请稍等
    猜你喜欢
    • 1970-01-01
    • 2012-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多