2014-11-10 2 views
1

한 줄에 수백 줄의 레거시 SQL 문을 받았습니다. 각 SQL은 공유 된 Models 프로젝트에서 고유 한 POCO를 사용하여 코드에 매핑됩니다. 예를 들어전체 빈혈 -이 데이터를 내 모델에서 어디로 옮길 수 있습니까?

Models 프로젝트에 equivilent POCO을 가지고 Select Name, Birthday From People는 SQL : 내 DAL에서

public class BirthdayPerson : SqlResultBase { 
    public string Name { get; set; } 
    public datetime Birthday { get; set; } 

    //SqlResultBase abstraction: 
    public string HardcodedSql { get { 
     return "Select Name, Birthday From People"; 
    }} 
} 

, 나는 그 <T>는 SQL의 POCO를 나타내는 하나의 범용의 SQL 주자 있습니다.

public IEnumerable<T> GetSqlResult<T>() where T : SqlResultBase, new() { 
    return context.Database.SqlQuery<T>((new T()).HardcodedSql); 
} 

문제는 내 Models 라이브러리 응용 프로그램을 통해 사용하는 것이, 그리고 그 HardcodedSql 속성에 응용 프로그램을 통해 노출 된 SQL을 원하지 않는 : 그래서 내 비즈니스 로직은 GetSqlResult<BirthdayPerson>()를 호출 할 수 있습니다.

Suamere's Domain

+0

클래스에서 함수를 만들고 함수에서 결과를 반환하면 원시 변수를 사적인 변수에 넣고 모든 곳에 노출시키지 않으면 도움이되지 않을까요? –

+0

거의 대단한 것 같습니다. 당신이 제안하는 것을 이해하는 한, 프론트 엔드가 여전히 메서드를 호출하고 노출 된 SQL을 읽을 수 있다고 확신합니다. – Suamere

+0

당신은 그 가정에 맞을 것입니다 :) –

답변

1

처음에는 DAL에 실제로 속한 SQL에서 모델 (즉 POCO)을 분리해야합니다. Inversion of Control은이 작업을 수행하는 올바른 방법입니다. 일반 SQL 러너 대신 IoC 컨테이너의 매핑을 추상 저장소 (예 : IRepository<MyPOCO>)에서 SQL이 포함 된 구현에 등록하는 것이 좋습니다.

편집 : 이름 규칙, 예를 들어, 임베디드 리소스 파일의 집합에

  • 장소 DAL 내부에 별도의 파일 (들)에 대한 모든 SQL을, 예를 들어 :이 가능한 솔루션을보다 구체적으로 레거시 - {0} .sql 여기서 {0}은 POCO의 이름입니다.
  • POCO 이름을 키로 사용하고 자원 세트에서 해당 레거시 {0} .sql 파일을 선택하는 레거시 저장소의 일반 구현을 작성하십시오. ORM과 같은 다른 데이터 액세스 기술을 사용하는 다른 구현도있을 수 있습니다.
  • 컴포지션 루트 레지스터에서 명시 적으로 레거시 POCO에서 레거시 구현으로의 매핑은 IRepository<MyPOCO1> => LegacyRepo<MyPOCO1>; IRepository<MyPOCO2> => LegacyRepo<MyPOCO2>; etc입니다. 또한 비 레거시 엔티티의 다른 매핑을 다른 저장소 구현에 등록 할 수 있습니다.
+0

또한 루이 루이스 (Louis Lewis)가 제안한 것처럼 SQL 뷰로 이동할 수도 있습니다. 그런 다음 저장소 구현은 원시 SQL 문 – neleus

+0

을 포함하지 않고 뷰를 참조합니다. SQL은 POCO에 속하지 않으며 대신 DAL에 있어야합니다. 그것이 질문의 요점입니다. 현재 Composition Root는 로컬 app_start 또는 서비스 app_start에 있으며 컴포지션은 constructor-injection을 사용하여 모든 수준에서 종속성 주입을 제공합니다. 좋은 대답이 될 수있는 부분은 "SQL이 포함 된 구현"이라고 말하는 부분에 대한 정교함입니다. 제네릭을 없애고 SQL 표현식과'Type' (제네릭의 두 변수) 이외의 모든 유형에 대해 중복 함수를 만드는 것을 의미합니까? – Suamere

+0

아니요, 많은 오버로드 된 (또는 중복 된) 메소드가 오픈 클로즈 (Open-Closed) 원칙을 위반합니다. Generic SQL Runner와 비슷한 하나의 일반적인 구현이 필요하고 각 구체적인 매핑에 구체적인 SQL을 주입해야합니다 :'IRepository => (RepoImpl + POCO1에 해당하는 SQL); IRepository => (RepoImpl + POCO2에 해당하는 SQL); etc. – neleus

1

간단한 솔루션 HardcodedSqlinternal 대신 public 그래서 그것은 DAL 프로젝트 내에서만 볼 수의 수 있도록하는 것입니다 :

내가 사용하고 아키텍처입니다. DAL이 모델과 별도의 프로젝트 인 경우 InternalsVisibleTo을 사용하여 프로젝트에 노출시킬 수 있습니다. 이는 프로젝트 구조를 적절하게 구성 할 수 있다고 가정합니다.

+0

분명히 처음에는 올바르게 읽지 않았습니다. 빨리 InternalsVisibleTo를 살펴보고 이것으로 돌아가겠습니다. – Suamere

+0

아, 그래, 지금 기억해. 필자는 InternalsVisibleTo에 대해 아는 것을 버렸다고 생각한다. 내 마음 속에서 코드 냄새를 나타낼 것이기 때문이다. 현재 상황의 경우에는 분명히 코드 냄새가 있으며 나는 그것을 좋아하지 않습니다. 따라서 InternalsVisibleTo가 도움이되는 동안, 나는 악취를 없애기위한 해결책을 찾고 있습니다. 그것은 또한 주어진 요구 사항에 대해 피할 수없는 것이 가능 합니다만, 그럴 수는 없으며 단지 뭔가를 바라 볼뿐입니다. 솔리드 리 팩터가 여기에 순서대로있을 수 있으며, 그 길을 따라 가면 완벽한 해답이 될 것입니다. – Suamere

+0

프로젝트 구조는 무엇입니까? Model, DAL, Business Layer에 대해 이미 별도의 프로젝트가 있습니까? –

1

아마도이 질문을 처리 할 수있는 두 가지 방법을 제안합니다.

첫 번째 방법은 sql에 액세스하는 방법을 변경하고 메서드에서 로컬로 호출을 래핑하는 것입니다. 따라서 클래스에는 public IEnumerable GetFromSql()이라는 함수가있을 수 있습니다.이 함수는 컨텍스트에서 전달하거나 새 함수를 만들 수 있습니다. 프로젝트에서 EF를 어떻게 설정했는지 모르겠습니다. 이런 식으로 원시 SQL을 공개적으로 공개하지는 않을 것입니다. 아마도 private 변수 나 로컬 상수로 만들고 함수 내에서 액세스 할 수 있습니다.

두 번째 옵션으로 실제로이 작업을 수행 한 결과 모든 SQL을 뷰로 이동하고 액세스 할 때 EF를 사용했습니다. 그런 식으로 내 코드에 SQL 오염이 발생하지 않았습니다. 모델이 이미 있음을 확인하면 뷰를 호출 한 결과가 이미 가지고있는 유형과 일치합니다.

+0

Views를 사용하는 것은 좋은 일이지만, 회사에서 코드를 배치 할 SQL을 제공했습니다. 훌륭한 제안이지만 DB에서 트리거, 뷰어, 저장된 Procs 등을 사용하는 것을 거부합니다. 그래, 그 제안을 주셔서 감사합니다. – Suamere

관련 문제