이 질문의 답은 "Including a Method class inside an Expression"입니다. 이 질문은 이미 그 해답을 갖고있는 것처럼 "이 문제에 대한 해결책을 찾을 수있는 방법"이 아닙니다. 내 질문은 "캡쳐 된 변수를 두 번 이상 사용하지만 하나의 평가 내에서 변수를 반복적으로 쿼리하지 않는 Expression
을 어떻게 쓰는지"입니다.Entity Framework의 식에서 다양한 값 사용
시간이 지남에 따라 달라질 수있는 속성 값을 가지거나 매우 비용이 많이 들지만 Expression 쿼리에서 여러 번 사용할 올바른 방법은 무엇입니까?
내가 엔티티 프레임 워크 소스가 동일한 쿼리에 의해 두 번 쿼리 위의 코드에서namespace Sandbox_Console
{
public class Program
{
static void Main(string[] args)
{
using (var ctx = new Context())
{
var selectExpression = GetSelect();
var query = ctx.Sources.Select(selectExpression);
var queryText = query.ToString();
var result1 = query.First();
var result2 = query.First();
var goodResult = (result1.Id != result2.Id && result1.Id == (result1.Prop - 1));
if(!goodResult)
throw new InvalidDataException();
}
}
static public Expression<Func<Source, Result>> GetSelect()
{
var foo = new Foo();
return source => new Result {Id = source.Id + foo.PropertyThatVaries, Prop = foo.PropertyThatVaries};
}
}
//...
}
예를
으로 보여 드리겠습니다,하지만 매개 변수 전달 일부에 대한 두 개의 서로 다른 값을 가져야한다. 다음은 쿼리SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Id] + @p__linq__0 AS [C1],
@p__linq__1 AS [C2]
FROM [dbo].[Sources] AS [Extent1]
문제는
@p__linq__0
입니다
및 @p__linq__1
에서 생성되는 SQL은 PropertyThatVaries
재산이 후속 호출에서 두 개의 서로 다른 값으로되어있다.
다양한 속성을 쿼리에 직접 입력하지 않아도 비슷한 결과를 얻을 수 있지만 그럴 경우 후속 쿼리에서 다른 값을 얻지 못합니다.
static public Expression<Func<Source, Result>> GetSelect()
{
var foo = new Foo();
var tmp = foo.PropertyThatVaries;
return source => new Result { Id = source.Id + tmp, Prop = tmp };
//Now fails the "result1.Id != result2.Id" test.
}
당신은 SQL이 닮은 LINQ 문 것에 대해 갈 것이라고 어떻게
:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Id] + @p__linq__0 AS [C1],
@p__linq__0 AS [C2]
FROM [dbo].[Sources] AS [Extent1]
을하지만 여전히 foo.PropertyThatVaries
에서 현재 값을 가지고? 여기
이 테스트 프로그램의 전체 complileable 버전입니다, 그것은에서 만들어진 .NET 4.5
using System;
using System.Data.Entity;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
namespace Sandbox_Console
{
public class Program
{
static void Main(string[] args)
{
using (var ctx = new Context())
{
var selectExpression = GetSelect();
var query = ctx.Sources.Select(selectExpression);
var queryText = query.ToString();
var result1 = query.First();
var result2 = query.First();
var goodResult = (result1.Id != result2.Id && result1.Id == (result1.Prop + 1));
if(!goodResult)
throw new InvalidDataException();
}
}
static public Expression<Func<Source, Result>> GetSelect()
{
var foo = new Foo();
var tmp = foo.PropertyThatVaries;
return source => new Result { Id = source.Id + tmp, Prop = tmp };
//return source => new Result {Id = source.Id + foo.PropertyThatVaries, Prop = foo.PropertyThatVaries};
}
}
public class Context : DbContext
{
public Context()
{
Database.SetInitializer<Context>(new Init());
}
public DbSet<Source> Sources { get; set; }
}
public class Init : DropCreateDatabaseAlways<Context>
{
protected override void Seed(Context context)
{
base.Seed(context);
context.Sources.Add(new Source() { Id = 1 });
}
}
public class Source
{
public int Id { get; set; }
}
public class Result
{
public int Id { get; set; }
public int Prop { get; set; }
}
public class Foo
{
public Foo()
{
rnd = new Random();
}
public int PropertyThatVaries
{
get
{
//This could also be a "Expensive" get. Un-comment the next line to simulate.
//Thread.Sleep(1000);
return rnd.Next(1, 100000);
}
}
private Random rnd;
}
}
foo.PropertyThatVaries (귀하의 경우 int) GetSelect의 매개 변수를 만든 다음 필요에 따라 호출 루틴에 캐시합니까? –
로컬 변수를 사용하여 블록 표현식을 만들 수는 있지만 EF가이를 이해할 수 있을지는 의문입니다. – svick
솔루션이 자체 Expression Tree를 작성해야한다고 생각합니다. 다양한 조합을 시도하는 데 약 2 시간을 소비하지만, 수행 방법을 정확하게 파악하지 않아도됩니다. –