2011-06-17 24 views
1

私はLinq式で左外部結合クエリを作成しようとしていますが、今は本当に壁に当たっています。Linq式で左外部結合

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発現ウィッヒを作成していない

は何を達成したいことは、次のクエリです。 (私はここSOMコード取り残さ):

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"))); 

をしかし、私はDefaultIfEmptyを追加しようとしているSelectManyメソッドで私が言って例外を取得:

種類は、一般的な方法「DefaultIfEmpty」 'System.Linq.Queryable'は で、指定された型 の引数と引数と互換性があります。 メソッドが非ジェネリックである場合は、タイプ の引数を指定しないでください。

私は、typeparamsをIQueryableからIEnumerableに切り替えようとしましたが、イベントはEnumerable.DefaultIfEmptyを不運に呼び出すことを試みました。おそらく、PropertyExpressionに何か問題がありますか?

+0

これを拡張メソッドにすることはできますか?私は多くの人々が恩恵を受けると思います – jaywayco

答えて

0

Expression.Callメソッドの型パラメータが誤って定義されていました。 IQueryable<DataObjectField>ではなく、DataObjectFieldのみでした。これがそれを修正したものです。

MethodCallExpression collectionCallExpression = 
    Expression.Call(
     typeof(Enumerable), 
     "DefaultIfEmpty", 
     new System.Type[] 
     { 
      typeof(DataObjectField) 
     }, 
     Expression.Property(collectionParameter, newResultType.GetProperty("DataObjectFields")) 
+0

私の解決策を試しましたか? – Aducci

+0

@Aducci、はい、主な問題は、型引数に正しい型を設定しなかったことです。 –

0

Expression.Callのオーバーロードは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); 
関連する問題