1

Linq Expressions を使用して左外部結合クエリを作成しようとしていますが、今は本当に壁にぶつかっています。

私が達成したいのは、次のクエリです。

var q =
    from i in ProcessInstances

    join dof1 in Queries.DataObjectFieldsQuery(this) on new { instanceId = i.ObjectID, dataId = fields[0,0], fieldId = fields[0,1] } equals new { instanceId = dof1.ProcessInstanceObjectID, dataId = dof1.DataID, fieldId = dof1.FieldID } into dofs1
    from dof1 in dofs1.DefaultIfEmpty()

    join dof2 in Queries.DataObjectFieldsQuery(this) on new { instanceId = i.ObjectID, dataId = fields[1,0], fieldId = fields[1,1] } equals new { instanceId = dof2.ProcessInstanceObjectID, dataId = dof2.DataID, fieldId = dof2.FieldID } into dofs2
    from dof2 in dofs2.DefaultIfEmpty()

    join dof3 in Queries.DataObjectFieldsQuery(this) on new { instanceId = i.ObjectID, dataId = fields[2,0], fieldId = fields[2,1] } equals new { instanceId = dof3.ProcessInstanceObjectID, dataId = dof3.DataID, fieldId = dof3.FieldID } into dofs3
    from dof3 in dofs3.DefaultIfEmpty()

    select new WorkitemListModel
    {
        InstanceId = i.ObjectID,
        FormFieldValue1 = dof1.FieldValue,
        FormFieldValue2 = dof2.FieldValue,
        FormFieldValue3 = dof3.FieldValue,
    };

次のクラスを定義しました。

public class WorkitemListModel
{
    public string InstanceId { get; set; }
    public string FormFieldValue1 { get; set; }
    public string FormFieldValue2 { get; set; }
    public string FormFieldValue3 { get; set; }
}

public class DataObjectField
{
    public string ProcessInstanceObjectID { get; set; }
    public string DataID { get; set; }
    public string FieldID { get; set; }
    public string FieldValue { get; set; }
}

public class ModelWithFields<TModel>
{
    public IEnumerable<DataObjectField> DataObjectFields { get; set; }
    public TModel Model { get; set; }
}

public class OuterKeySelector
{
    public string instanceId { get; set; }
    public string dataId { get; set; }
    public string fieldId { get; set; }
}

コンパイル エラーが発生しない GroupJoin 式を作成しました。(私はここにいくつかのコードを残しました):

var q = dc.Instances;

System.Type modelType = typeof(ModelWithFields<>);
System.Type outerKeyType = typeof(WorkitemListModel);
System.Type resultType = modelType.MakeGenericType(outerKeyType);

//... MemberInitExpression and Expression.Bind

q = q.Provider.CreateQuery(
    Expression.Call(
        typeof(Queryable), 
        "GroupJoin",
        new[] 
        { 
            typeof(WorkitemListModel), 
            typeof(DataObjectField), 
            typeof(OuterKeySelector),
            resultType,
        },
        query.Expression,
        Expression.Constant(Queries.DataObjectFieldsQuery(dc)),
        Expression.Quote(outerLambda),
        Expression.Quote((Expression<Func<DataObjectField,OuterKeySelector>>)(
            (DataObjectField dof) => 
                new OuterKeySelector
                {
                    instanceId = dof.ProcessInstanceObjectID, 
                    dataId = dof.DataID, 
                    fieldId = dof.FieldID
                })),
        Expression.Quote(resultLambda)));


// selectmany expression
// collectionSelector lambda -- temp.DataObjectFields.DefaultIfEmpty()
ParameterExpression collectionParameter = Expression.Parameter(resultType, "temp");

// This throw an exception
MethodCallExpression collectionCallExpression = 
    Expression.Call(
        typeof(Queryable),
        "DefaultIfEmpty",
        new System.Type[]
        {
            typeof(IQueryable<>).MakeGenericType(typeof(DataObjectField))
        },
        Expression.Property(collectionParameter, resultType.GetProperty("DataObjectFields")));

しかし、 SelectMany メソッドで DefaultIfEmpty を追加しようとしていますが、次のような例外が発生します。

型 'System.Linq.Queryable' のジェネリック メソッド 'DefaultIfEmpty' は、指定された型引数および引数と互換性がありません。メソッドが非ジェネリックの場合は、型引数を指定しないでください。

typeparams を IQueryable から IEnumerable に切り替えてみましたが、イベントが Enumerable.DefaultIfEmpty を呼び出そうとしましたが、うまくいきませんでした。おそらく、PropertyExpression に何か問題があるのでしょうか?

4

2 に答える 2

0

Expression.Callメソッドの誤った型パラメーターを定義しました。それIQueryable<DataObjectField>だけではありませんでしたDataObjectField。これがそれを修正したものです。

MethodCallExpression collectionCallExpression = 
    Expression.Call(
        typeof(Enumerable),
        "DefaultIfEmpty",
        new System.Type[]
        {
            typeof(DataObjectField)
        },
        Expression.Property(collectionParameter, newResultType.GetProperty("DataObjectFields"))
于 2011-06-20T07:02:47.403 に答える
0

Expression.Call using の別のオーバーロードを好みMethodInfoます。これは、私が取り組んでいる簡単な例です。

Expression constant = Expression.Constant(new string[] { "a", "b" });
MethodInfo methodInfo = typeof(Enumerable).GetMethods().FirstOrDefault(c => (c as MethodInfo).Name == "DefaultIfEmpty");
methodInfo = methodInfo.MakeGenericMethod(typeof(string));

MethodCallExpression methodExpression = Expression.Call(methodInfo, constant);
于 2011-06-17T18:37:29.543 に答える