Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linq 如何分配IQueryable的属性值<;T>;?_Linq_Entity Framework_Entity_Expression Trees_Iqueryable - Fatal编程技术网

Linq 如何分配IQueryable的属性值<;T>;?

Linq 如何分配IQueryable的属性值<;T>;?,linq,entity-framework,entity,expression-trees,iqueryable,Linq,Entity Framework,Entity,Expression Trees,Iqueryable,我首先使用实体框架4.1代码。在我的实体中,我有三个日期/时间属性: public class MyEntity { [Key] public Id { get; set; } public DateTime FromDate { get; set; } public DateTime ToDate { get; set; } [NotMapped] public DateTime? QueryDate { get; set; }

我首先使用实体框架4.1代码。在我的实体中,我有三个日期/时间属性:

public class MyEntity
{
    [Key]
    public Id { get; set; }

    public DateTime FromDate { get; set; }

    public DateTime ToDate { get; set; }

    [NotMapped]
    public DateTime? QueryDate { get; set; }

    // and some other fields, of course
}
在数据库中,我总是填充从/到日期。我使用一个简单的where子句查询它们。但是在结果集中,我想包括我查询的日期。我需要坚持这一点,以便其他一些业务逻辑能够工作

我正在研究一种扩展方法来实现这一点,但我遇到了一些问题:

public static IQueryable<T> WhereDateInRange<T>(this IQueryable<T> queryable, DateTime queryDate) where T : MyEntity
{
    // this part works fine
    var newQueryable = queryable.Where(e => e.FromDate <= queryDate &&
                                            e.ToDate >= queryDate);

    // in theory, this is what I want to do
    newQueryable = newQueryable.Select(e =>
                                           {
                                               e.QueryDate = queryDate;
                                               return e;
                                           });
    return newQueryable;
}
所以问题是,我如何转换表达式树,我已经必须包含这个额外的属性赋值?我已经研究了IQueryable.Expression和IQueryable.Provider.CreateQuery,其中有一个解决方案。是否可以将赋值表达式附加到现有表达式树?我对表达式树方法不太熟悉,无法理解这一点。有什么想法吗

示例用法

澄清一下,目标是能够执行如下操作:

SELECT *, @QueryDate as QueryDate
FROM MyEntities
WHERE @QueryDate BETWEEN FromDate AND ToDate
var entity = dataContext.Set<MyEntity>()
                        .WhereDateInRange(DateTime.Now)
                        .FirstOrDefault();
var entity=dataContext.Set()
.WhereDateInRange(DateTime.Now)
.FirstOrDefault();
并将DateTime.Now保存到结果行的QueryDate中,而不会从数据库查询返回多行。(对于IEnumerable解决方案,在FirstOrDefault选择我们想要的行之前,会返回多行。)

另一个想法


我可以继续将QueryDate映射为一个真实的字段,并将其DatabaseGeneratedOption设置为Computed。但是,我需要某种方法将“@QueryDate as QueryDate”注入EF的select语句创建的SQL中。因为它是计算出来的,所以EF不会在更新或插入期间尝试提供值。那么,我如何将自定义SQL注入select语句呢?

不,我认为没有解决方案。确实,您可以修改表达式树,但您将得到与linq查询完全相同的异常,因为该查询实际上是您将在表达式树中构建的查询。问题不在表达式树中,而在映射中。EF无法将
QueryData
映射到结果。此外,您正在尝试进行投影。无法对映射的实体进行投影,并且无法从方法返回匿名类型

您当然可以执行您提到的选择,但您无法将其映射到您的实体。您必须为此创建一个新类型:

var query = from x in context.MyData
            where x.FromDate <= queryDate && x.ToDate >= queryDate
            select new MyDateWrapper
                {
                   MyData = x,
                   QueryDate = queryDate
                };
var query=来自context.MyData中的x
其中x.FromDate=queryDate
选择新建MyDateWrapper
{
MyData=x,
QueryDate=QueryDate
};

拉迪斯拉夫是绝对正确的。但是,由于您显然希望回答问题的第二部分,下面是如何使用Assign。不过,这对EF不起作用

using System;
using System.Linq;
using System.Linq.Expressions;

namespace SO5639951
{
    static class Program
    {
        static void Main()
        {
            AdventureWorks2008Entities c = new AdventureWorks2008Entities();
            var data = c.Addresses.Select(p => p);

            ParameterExpression value = Expression.Parameter(typeof(Address), "value");
            ParameterExpression result = Expression.Parameter(typeof(Address), "result");
            BlockExpression block = Expression.Block(
                new[] { result },
                Expression.Assign(Expression.Property(value, "AddressLine1"), Expression.Constant("X")),
                Expression.Assign(result, value)
                );

            LambdaExpression lambdaExpression = Expression.Lambda<Func<Address, Address>>(block, value);

            MethodCallExpression methodCallExpression = 
                Expression.Call(
                    typeof(Queryable), 
                    "Select", 
                    new[]{ typeof(Address),typeof(Address) } , 
                    new[] { data.Expression, Expression.Quote(lambdaExpression) });

            var data2 = data.Provider.CreateQuery<Address>(methodCallExpression);

            string result1 = data.ToList()[0].AddressLine1;
            string result2 = data2.ToList()[0].AddressLine1;
        }
    }
}
使用系统;
使用System.Linq;
使用System.Linq.Expressions;
名称空间SO5639951
{
静态类程序
{
静态void Main()
{
AdventureWorks2008Entities c=新的AdventureWorks2008Entities();
var data=c.Addresses.Select(p=>p);
ParameterExpression值=Expression.Parameter(类型(地址),“值”);
ParameterExpression结果=Expression.Parameter(类型(地址),“结果”);
BlockExpression block=Expression.block(
新[]{result},
Expression.Assign(Expression.Property(值,“AddressLine1”)、Expression.Constant(“X”),
表达式.赋值(结果、值)
);
LambdaExpression LambdaExpression=Expression.Lambda(块,值);
MethodCallExpression MethodCallExpression=
表情,打电话(
类型(可查询),
“选择”,
新[]{typeof(地址),typeof(地址)},
新[]{data.Expression,Expression.Quote(lambdaExpression)};
var data2=data.Provider.CreateQuery(methodCallExpression);
字符串result1=data.ToList()[0].AddressLine1;
字符串result2=data2.ToList()[0].AddressLine1;
}
}
}
更新1

这里是经过一些调整后的相同代码。我读过上面代码中EF阻塞的“Block”表达式,以绝对清晰地证明EF不支持的是“Assign”表达式。请注意,Assign原则上适用于泛型表达式树,EF提供程序不支持Assign

using System;
using System.Linq;
using System.Linq.Expressions;

namespace SO5639951
{
    static class Program
    {
        static void Main()
        {
            AdventureWorks2008Entities c = new AdventureWorks2008Entities();

            IQueryable<Address> originalData = c.Addresses.AsQueryable();

            Type anonType = new { a = new Address(), b = "" }.GetType();

            ParameterExpression assignParameter = Expression.Parameter(typeof(Address), "value");
            var assignExpression = Expression.New(
                anonType.GetConstructor(new[] { typeof(Address), typeof(string) }),
                assignParameter,
                Expression.Assign(Expression.Property(assignParameter, "AddressLine1"), Expression.Constant("X")));
            LambdaExpression lambdaAssignExpression = Expression.Lambda(assignExpression, assignParameter);

            var assignData = originalData.Provider.CreateQuery(CreateSelectMethodCall(originalData, lambdaAssignExpression));
            ParameterExpression selectParameter = Expression.Parameter(anonType, "value");
            var selectExpression = Expression.Property(selectParameter, "a");
            LambdaExpression lambdaSelectExpression = Expression.Lambda(selectExpression, selectParameter);

            IQueryable<Address> finalData = assignData.Provider.CreateQuery<Address>(CreateSelectMethodCall(assignData, lambdaSelectExpression));

            string result = finalData.ToList()[0].AddressLine1;
        }        

        static MethodCallExpression CreateSelectMethodCall(IQueryable query, LambdaExpression expression)
        {
            Type[] typeArgs = new[] { query.ElementType, expression.Body.Type };
            return Expression.Call(
                typeof(Queryable),
                "Select",
                typeArgs,
                new[] { query.Expression, Expression.Quote(expression) });

        }
    }
}
使用系统;
使用System.Linq;
使用System.Linq.Expressions;
名称空间SO5639951
{
静态类程序
{
静态void Main()
{
AdventureWorks2008Entities c=新的AdventureWorks2008Entities();
IQueryable originalData=c.Addresses.AsQueryable();
键入anonType=new{a=newaddress(),b=”“}.GetType();
ParameterExpression assignParameter=表达式.参数(类型(地址),“值”);
var assignExpression=Expression.New(
anonType.GetConstructor(新的[]{typeof(地址),typeof(字符串)}),
赋值参数,
Expression.Assign(Expression.Property(assignParameter,“AddressLine1”)、Expression.Constant(“X”));
LambdaExpression lambdassignexpression=Expression.Lambda(assignExpression,assignParameter);
var assignData=originalData.Provider.CreateQuery(CreateSelectMethodCall(originalData,lambdassignExpression));
ParameterExpression selectParameter=Expression.Parameter(输入“值”);
var selectExpression=Expression.Property(selectParameter,“a”);
LambdaExpression lambdaSelectExpression=Expression.Lambda(selectExpression,selectParameter);
IQueryable finalData=assignData.Provider.CreateQuery(CreateSelectMethodCall(assignData,lambdaSelectExpression));
字符串结果
public class MyEntity
{       
    private DateTime? _queryDate;

    [ThreadStatic]
    internal static DateTime TempQueryDate;

    [NotMapped]
    public DateTime? QueryDate
    {
        get
        {
            if (_queryDate == null)
                _queryDate = TempQueryDate;
            return _queryDate;
        }
    }

    ...       
}

public static IQueryable<T> WhereDateInRange<T>(this IQueryable<T> queryable, DateTime queryDate) where T : MyEntity
{
    MyEntity.TempQueryDate = queryDate;

    return queryable.Where(e => e.FromDate <= queryDate && e.ToDate >= queryDate);
}
 configuration.CreateMap(typeof(MyEntity), typeof(MyEntity))
    .ForMember(nameof(Entity.QueryDate), opt.MapFrom(src => DateTime.Now));
queryable.ProjectTo<MyEntity>();