2009-04-02 3 views
13

이 토론을 위해서는 두 개의 개체 A & B가 있습니다. 공통된 관계 또는 외래 키를 통해 이러한 개체 (테이블)를 조인 할 수 있습니다. linq을 사용하여이 조인을 수행하고 있으며 결과 세트에서 ObjectA 만 리턴하려고합니다. 그러나 OBJA의 속성을 Join 중에 ObjectB의 데이터로 업데이트하여 LINQ 쿼리에서 벗어난 ObjectAs가 선택 항목 인 저장소의 원래 상태와 "약간"다르기를 바랍니다. 여기 LINQ 인라인 등록 중 속성 업데이트

내 쿼리, 당신은 그냥 objectA.SomeProperty처럼 뭔가를 할 수 있도록하고 싶습니다 것을 알 수있다 = objectB.AValueIWantBadly 나는 내 선택에 새를하고 새로운 OBjectAs을 회전 할 수 알고

, 가능하면 그것을 피하고 단순히 필드를 업데이트하고 싶습니다.

return from objectA in GetObjectAs() 
    join objectB in GetObjectBs() 
      on objectA.Id equals objectB.AId 
      // update object A with object B data before selecting it 
    select objectA; 

답변

22

class ClassA { 
    public ClassA UpdateWithB(ClassB objectB) { 
    // Do the update 
    return this; 
    } 
} 

다음

return from objectA in GetObjectAs() 
    join objectB in GetObjectBs() 
      on objectA.Id equals objectB.AId 
      // update object A with object B data before selecting it 
    select objectA.UpdateWithB(objectB); 

편집 사용하여를 ClassA에 업데이트 방법을 추가

또는 같은 지역 람다 함수를 사용

Func<ClassA, ClassB, ClassA> f = ((a,b)=> { a.DoSomethingWithB(b); return a;}); 
return from objectA in GetObjectAs() 
     join objectB in GetObjectBs() 
     on objectA.Id equals objectB.AId 
     select f(objectA , objectA); 
+0

이것은 linq-to-sql에서 작동하지 않습니다. '[NotMapped]'속성을 가진 속성이 있습니다. – th1rdey3

0

let 문을 사용할 수 있습니까? (안 내 dev에 기계에서 자신이 테스트하는) 단어에서

return from objectA in GetObjectAs() 
join objectB in GetObjectBs() 
on objectA.Id equals objectB.AId 
let objectA.SomeProperty = objectB.AValueIWantBadly 
select objectA; 
+0

아니, 당신은 할 수 없습니다; 새로운 변수 만 생성합니다 - 할당을하지 않습니다. –

+0

나는 위의 코멘트가 정확한지 ... 이것을 시도했다 ... 안돼. – JPrescottSanders

2

"테이블"을, 당신은 데이터베이스에서 데이터를 얻고있는 것처럼 들린다. 어떤 경우에; 아니오 : 당신은 이것을 할 수 없습니다. 당신이 할 것 수있는 가장 가까운 개체와 여분의 열을 선택하고 나중에 속성을 업데이트 : 뭐한다면

var qry = from objectA in GetObjectAs() 
      join objectB in GetObjectBs() 
      on objectA.Id equals objectB.AId 
      select new { A = objectA, 
       objectB.SomeProp, objectB.SomeOtherProp }; 

foreach(var item in qry) { 
    item.A.SomeProp = item.SomeProp; 
    item.A.SomeOtherProp = item.SomeOtherProp; 
    // perhaps "yield return item.A;" here 
} 

을 LINQ를 - 투 - 객체, 당신은 유창 함께 할 수있는 몇 가지 해키 방법은 아마도이 있습니다 APIs - 꽤 아니지만. - (편집 this other reply 같은)

+0

DB에서 가져 왔지만 이러한 변경 사항이 DB에 다시 게시되는 것을 원하지 않습니다.이 "새로운"객체 A가 다른 데이터를 가지고 다니는 것을 허용합니다. – JPrescottSanders

1

먼저 LinqExtensions라는 클래스를 만들어 Linq에 Each 옵션을 추가합니다.

public static class LinqExtensions 
    { 
    public static void Each<T>(this IEnumerable<T> source, Action<T> method) 
    { 
     foreach (var item in source) 
     { 
     method(item); 
     } 
    } 
    } 

그런 다음 결합을 사용하여 원본 개체가 포함 된 새 개체 목록을 적절한 값으로 반환 할 수 있습니다. 각 객체를 반복하여 매개 변수로 값을 할당하거나 각 객체에 전달할 수 있습니다.

할당 예 :

objectA.Join(objectB,a=>a.Id,b=>b.Id,(a,b) => new {a,b.AValueIWant}).Each(o=>o.a.SomeProperty=o.AValueIWant); 

매개 변수 전달 예 :

objectA.Join(objectB,a=>a.Id,b=>b.Id,(a,b) => new {a,b.AValueIWant}).Each(o=>o.a.SomeMethod(o.AValueIWant)); 

이의 좋은 점은 ObjectA 및 ObjectB가 같은 유형이 될 필요가 없다는 것입니다. 나는 룩업 (lookup)과 같은 Dictionary에 조인 된 객체의리스트를 가지고이를 수행했다. 나쁜 일은 무슨 일이 일어나고 있는지 분명하지 않다는 것입니다. 각 확장을 건너 뛰고 이렇게 작성하는 것이 좋습니다.

foreach(var change in objectA.Join(objectB,a=>a.Id,b=>b.Id,(a,b) => new {a,b.AValueIWant})) 
{ 
    change.a.SomeProperty = change.AValueIWant; 
    change.a.SomeMethod(change.AValueIWant); 
} 

하지만 더 명확하게 아마 이런 짓을 했을까 :

foreach(var update in objectA.Join(objectB,objectA=>objectA.Id,objectB=>objectB.Id,(objectA,objectB) => new {objectA, Value = objectB.AValueIWant})) 
{ 
    update.objectA.SomeProperty = update.Value; 
} 

가 읽기 전용이 될 것이며,이 작품 유일한 이유가 있기 때문에 당신은 당신의 새로운 오브젝트의 전체 ObjectA를 반환해야합니다 컬렉션의 개체가 참조되어 개체의 속성을 변경할 수 있습니다.

하지만 결국 LINQ 조인을 건너 뛰고 컬렉션을 반복하고 일치하는 항목을 찾는 것이 미래의 유지 관리에 도움이됩니다. LINQ는 대단 합니다만 망치를 가지고있을 때처럼 모든 것을 못 만들지는 않습니다. 컬렉션을 가지고있을 때 LINQ가 답이라는 것을 의미하지는 않습니다.

1

여기서 objectB의 해당 속성이 null 인 경우에도 objectA의 모든 데이터를 보유 할 수 있도록 여기에서 왼쪽 조인을 수행하고 있습니다. 따라서 objectB의 해당 속성이 null이면 objectA에서 수행 할 작업을 정의해야합니다. 나는이 진술을 두 세트의 데이터를 합치기 위해 항상 사용한다. objectA의 모든 속성을 철저히 나열 할 필요는 없으며 매핑 방법은 objectB로 업데이트하려는 값만 나열하면됩니다. objectA의 기존 값은 objectB에 대한 매핑이 정의되어 있지 않으면 안전합니다.

return from objectA in GetObjectAs() 
    join objectB in GetObjectBs() 
    on objectA.Id equals objectB.AId into combinedObj 
    from subObject in combinedObj.DefaultIfEmpty() 
    // update object A with object B data before selecting it 
    select ((Func<objectAType>)(() => 
    { 
     objectA.property = ((subObject == null) ? "Object B was null" : subObject.property); 
     objectA.property = ((subObject == null) ? "Object B was null" : subObject.property); 
     return objectA; 
    }))() 
0
당신이에 따라 시도 할 수

..

  var list1 = new List<ItemOne> 
         { 
          new ItemOne {IDItem = 1, OneProperty = "1"}, 
          new ItemOne {IDItem = 2, OneProperty = null}, 
          new ItemOne {IDItem = 3, OneProperty = "3"}, 
          new ItemOne {IDItem = 4, OneProperty = "4"} 
         }; 
     var list2 = new List<ItemTwo> 
         { 
          new ItemTwo {IDItem = 2, TwoProperty = "2"}, 
          new ItemTwo {IDItem = 3, TwoProperty = "3"}, 
         }; 


     var query = list1.Join(list2, l1 => l1.IDItem, l2 => l2.IDItem, (l1, l2) => 
     { 
      l1.OneProperty = l2.TwoProperty; 
      return l1; 
     });