2010-08-19 2 views
0

하는 데 도움이 번역 SQL 서버 UNION 구문이 필요하십니까 여기에 많은 잘못이 있습니다 - 그것은 단지 시작에 불과합니다. 그것은 위의 임시 열 또는 order by 조건과 제네릭/반환 형식 모호성을 고려하지 않는 것은 두 가지 다른 반환 형식을 이해하게 내 시도 :나는 아래 잘 작동 SQL을 LINQ

public List<T> GetSomething<T>(Int32 accountId) 
{ 
    List<T> result; 

    using (DataContext dc = _conn.GetContext()) 
    { 
     IEnumerable<Alert> alerts = (from a in dc.Alerts 
            where a.AccountId == accountId 
            select a); 
     IEnumerable<StatusUpdate> updates = (from s in dc.StatusUpdates 
              where s.AccountId == accountId 
              select s); 

     IEnumerable<T> obj = alerts.Union(updates); 

     result = obj.ToList(); 
    } 

    return result; 
} 

을 오전 데 문제가 있습니다 :

1) 내 선택에서 두 가지 유형 (경고 및 StatusUpdate)을 처리 중입니다. 결합 방법 (또는 반환 할 유형)을 잘 모르겠습니다. 제 생각에 이것들은 제네릭으로 해결할 수 있습니다. ?

2) 제 SQL에서이 코드는 (SELECT 10 AS Expr1) AS AlertTypeId이며 임시 열 AlertTypeId에 ​​값 10을 추가합니다 (Union이 Alert의 실제 열 AlertTypeId와 일치하도록 허용). LINQ에서 이와 같은 임시 열은 어떻게 이루어 집니까?/어떻게해야합니까?

도움 주셔서 감사합니다.

편집 --------------------------------- 편집 ---------- -------------------------------- EDIT

좋아요, 조금 더 있습니다. 아래는 제가 현재 가지고있는 것입니다. 친구 관계에 대한 업데이트를 반환하는 논리를 추가했음을 알 수 있습니다. 나는 또한 경고와 업데이트가 일치해야한다는 점을 감안할 때, 일반적인 유형의 IList 메소드를 만들었다. 호출 메소드에서 StatusUpdate를 전달합니다 (아래에서 더 자세히 설명합니다).

public IList GetUpdatesByAccountId<T>(Int32 accountId) 
{ 
    List<Friend> friends = _friendRepository.GetFriendsByAccountId(accountId); 

    using (DataContext dc = _conn.GetContext()) 
    { 
     // Get all the account ids related to this user 
     var friendAccountIds = 
      friends.Select(friend => friend.MyFriendsAccountId).Distinct(); 
      friendAccountIds = friendAccountIds.Concat(new[] { accountId }); 

     var updates = 
      dc.StatusUpdates.Where(s => s.AccountId.HasValue && friendAccountIds.Contains(s.AccountId.Value)).Select(
       s => new { Alert = (Alert)null, StatusUpdate = s}); 

     var alerts = 
      dc.Alerts.Where(a => a.AccountId == accountId).Select(
       a => new {Alert = a, StatusUpdate = (StatusUpdate) null}); 

     var obj = updates.Union(alerts).Take(100); 

     return obj.OrderByDescending(su => su.StatusUpdate.CreateDate).ToList(); 

    } 

} 

그리고, 호출 방법 :

public interface IAlertRepository 
    { 
     List<Alert> GetAlertsByAccountId(Int32 accountId); 
     void SaveAlert(Alert alert); 
     void DeleteAlert(Alert alert); 
    } 

public interface IStatusUpdateRepository 
    { 
     StatusUpdate GetStatusUpdateById(Int32 statusUpdateId); 
     List<StatusUpdate> GetStatusUpdatesByAccountId(Int32 accountId); 
     List<StatusUpdate> GetFriendStatusUpdatesByAccountId(Int32 accountId, Boolean addPassedInAccount); 
     void SaveStatusUpdate(StatusUpdate statusUpdate); 
     List<StatusUpdate> GetTopNStatusUpdatesByAccountId(Int32 accountId, Int32 number); 
     List<StatusUpdate> GetTopNFriendStatusUpdatesByAccountId(Int32 accountId, Int32 number, Boolean addPassedInAccount);   
    } 

현재 문제 :

protected void LoadStatus() 
{ 

    repStatusUpdates.DataSource = _statusRepository 
     .GetUpdatesByAccountId<StatusUpdate>(_userSession.CurrentUser.AccountId); 

    repStatusUpdates.DataBind(); 

} 

여기에 내가 LINQ를 통해 내 알림 및 StatusUpdate 테이블에 액세스하는 데 사용하고있는 저장소에 대한 인터페이스입니다 :

1)이 코드를 컴파일하면이 이상한 오류가 발생합니다 :

Unable to cast object of type 'System.Data.Linq.SqlClient.SqlNew' to type 'System.Data.Linq.SqlClient.SqlValue'.

거기에 명확한 해결책은 없지만 (적어도 내가 알 수있는) 읽을 수있는 유일한 설명은 this link입니다. 그러나 위의 LINQ 코드가 잘 보이지 않으면 어쨌든이 오류가 사라질 수 있습니다.

(SELECT 10 AS Expr1) AS AlertTypeId 

을하지만이 미성년자 :

2) 위의 코드는 여전히 원래 SQL에서이 줄을 차지하지 않습니다.

다시 도움을 청하십시오.

+0

그 이상한 오류 메시지는 아마도 LinqToSQL 쿼리가 LinqToSQL에 비해 너무 복잡하다는 것을 의미합니다. 테스트를 복잡하게 만들었지 만이 테스트를 작성한 사람은 누구도 설명하지 못했습니다. – erikkallen

+0

일반적인 방법으로 만들지는 모르겠다. 또한 SQL 쿼리에서 수행하는 작업이 아니기 때문에 유니온 작업 후에 테이크를 수행하지 않으려 고합니다. – Merritt

+0

StatusUpdate/Alert 쌍 중 하나가 항상 null 인 목록을 만드는 데 가장 큰 팬이 아닙니다. 여기서 anonynonous 타입의 사용은 데이터 바인딩 외부의 유용성을 제한 할 것이고 속성 값을 찾기 위해 리플렉션을 잠재적으로 필요로 할 것입니다. – Merritt

답변

1

(이 허용하지 않은 경우, 당신은 새로운 클래스를로이 중 하나 StatusUpdate에 경고를 변환하거나 만들거야, 내가 경고에 StatusUpdate 변환)이 시도 :

var alerts = (from a in dc.Alerts 
       where a.AccountId == accountId 
       select a); 
var updates = (from s in dc.StatusUpdates 
       where s.AccountId == accountId 
       select s) 
       .OrderByDescending(x => x.CreateDate) 
       .Take(100) 
       .Select(x => new Alert 
       { 
        Message = x.Percent.ToString(), 
        CreateDate = x.CreateDate, 
        AccountId = x.AccountId, 
        AlertTypeId = 10 // Is this right? 
       } 
       ); 

var obj = alerts.Union(updates); 

result = obj.ToList(); 

내가 마지막으로 선택하는 이유는 사용하지 않는 모든 결과에 대해 새 경고를 구성 할 필요가 없기 때문입니다.

경고 목록을 제공합니다.

이 상황에서 제네릭을 사용하는 것은 어려운 일입니다. 예를 들어, 당신은이 작업을 수행 할 수 없습니다

된 IQueryable 경고 = (_alerts에서이 a.AccountId == 계정 아이디는 선택 곳에서);

즉 암시 적으로는 T를 구현하거나 상속을 제한하려고해도 T.를 입력 변환하기 때문에 정적으로 정확히 무엇을 알 수있는 방법이 없기 때문에 당신은 여전히 ​​문제로 실행하겠습니다

public List<T> GetSomething<T>(Int32 accountId) where T : IAlert// Interface that both StatusUpdates and IAlert implement 
public List<T> GetSomething<T>(Int32 accountId) where T : Alert 
public List<T> GetSomething<T>(Int32 accountId) where T : AlertBase // Base class for both Status and Alert 

type T는 Alert 및 StatusUpdate에서 변환 할 수 있는지 알 수 없습니다. IAlert와

public List<IAlert> GetSomething(Int32 accountId) 

:

대안 명시 적으로 반환 형식으로 IAlert을 사용하는 것입니다 당신이 알림 및 StatusUpdate 모두 IAlert 구현이있는 경우

public interface IAlert 
{ 
    int AccountId { get; set; } 
    int AlertTypeId { get; set; } 
    DateTime CreateDate { get; set; } 
    string Message { get; set; } 
} 

, 당신은 너무 그것을 다시 수 :

이것은 알 수없는 typ를 전달하는 대신 걸리는 경로입니다. e를 구현하고 상속하는 것을 제한하려고 시도합니다. 그 유형으로 변환하는 것은 여전히 ​​유효하지 않을 수 있기 때문입니다.

+0

안녕하세요 메리트. 감사. 원래 SQL에서 수행하려고했던 모든 일에 답하는 것처럼 보이는 것처럼 코드가 마음에 들었습니다. 그러나 컴파일러는 "새로운"문장을 사용하여 여러 가지 다른 점에서 불평하고있었습니다. 늦게 슈퍼이며 자러 갈 필요가 있지만 내일 다시 방문하여 코드에 발생한 오류를 다시보고하겠습니다. 그 동안 현재 업데이트 된 코드를 게시했습니다. 다시 한번 감사드립니다. –

+0

작업 중 ... 지금 직장에서. – Merritt

+0

예, 그냥 'a'앞의 새 것을 제거하십시오. 수정 된 답변 – Merritt

0

동등한 유형의 시퀀스로만 유니온을 사용할 수 있습니다. 일반적인 유형의 순서로 경고 및 업데이트를 변환 한 다음 조합을 가져와야합니다. 익명 형식을 사용하여 그렇게 할 수 있습니다. 유형에 공통점이없는 경우 특히 유용합니다. 당신이 일반 필드가있는 경우이 알려진 필드를 포함 것을 제외하고

//this is a hack and probably not what you would want to use. 
var alerts = 
     from a in dc.Alerts 
     where a.AccountId == accountId 
     select new { Alert = a, StatusUpdate = (StatusUpdate)null }; 
var updates = 
     from s in dc.StatusUpdates 
     where s.AccountId == accountId 
     select new { Alert = (Alert)null, StatusUpdate = s }; 

//both are sequences of anonymous type with properties: 
// Alert (of type Alert) 
// StatusUpdate (of type StatusUpdate) 
var obj = alerts.Union(updates); 

, 당신은 여전히 ​​익명 형식을 사용하십시오.

var alerts = 
     from a in dc.Alerts 
     where a.AccountId == accountId 
     select new 
     { 
      a.Message, //assuming is a string 
      Status = (string)null, 
      a.CreateDate, 
      a.AccountId, 
      a.AlertTypeId //assuming is an int 
     }; 
var updates = 
     (from s in dc.StatusUpdates 
     where s.AccountId == accountId 
     select new 
     { 
      Message = (string)null, 
      s.Status, //assuming is a string 
      s.CreateDate, 
      s.AccountId, 
      AlertTypeId = 10 //this should handle the "10 AS AlertTypeId" part 
     }).OrderByDescending(s => s.CreateDate); 

var obj = alerts.Union(updates); 

키는 익명 형식이 모두 동일한 정확한 유형의 정확한 속성을가집니다. 그런 다음 둘 사이의 결합을 취할 수 있습니다.

+0

안녕하세요 Jeff. 감사. 나는 던져 넣은 공을 가지고 달려 가면서 위의 편집 내용을 게시했습니다. 나는 당신이 게시하려고하는 "common fields"코드를 좋아하지만 또한 s.Status와 a.Message가 필요합니다. 하나의 (임시) 열로 표시되는 메시지 (당신은 공통적이지 않다는 것이 맞습니다). 다시 한번 감사드립니다. –

+0

나는 당신이 그 부분을 어떻게 원했는지 확실하지 않았다. 내 대답을 업데이트했습니다. 요점은 두 세트의 유형을 완전히 동일하게 만드는 것입니다. –

+0

안녕하세요 Jeff. 무리 감사. Merritt에 대한 나의 반응 당 문제가 발생하고 있음을 알기 때문에이 메소드를 유형별로 만드는 방법을 알아 내려고 노력 중입니다. 이 작업을 수행하는 방법에 대한 추가 생각이 있으면 친절하게 알려주십시오. 그렇지 않으면, 내가 이것을 알아낼 때 나는 다시보고 할 것이다 ... 다시 감사한다! –

관련 문제