문제

저는 치과 의사가 특정 임상 활동에 대한 정보를 캡처할 수 있는 애플리케이션을 개발 중입니다.응용 프로그램은 고도로 사용자 정의할 수는 없지만(사용자 정의 작업 흐름이나 양식 없음) 몇 가지 기본적인 사용자 정의 기능을 제공합니다.고객은 미리 정의된 양식 필드를 자신만의 사용자 정의 양식 필드로 보강하도록 선택할 수 있습니다.관리자가 생성할 수 있는 필드 유형은 약 6개입니다(예:텍스트, 날짜, 숫자, 드롭다운 등).우리는 이 기능을 모델링하기 위해 지속성 측면에서 EAV(Entity-Attribute-Value)를 사용하고 있습니다.

애플리케이션의 다른 주요 기능 중 하나는 이러한 사용자 정의 필드에 대해 사용자 정의 쿼리를 생성하는 기능입니다.이는 원하는 수의 규칙(날짜 <= (현재 - 5일), '444'와 같은 텍스트, DropDown == 'ICU')을 생성할 수 있는 UI를 통해 수행됩니다.모든 규칙은 AND로 연결되어 쿼리를 생성합니다.

현재 구현(내가 "상속"한)은 객체 지향적이지도 않고 단위 테스트도 가능하지 않습니다.본질적으로 모든 무수한 규칙 유형을 복잡한 동적 SQL 문으로 직접 컴파일하는 단일 "신" 클래스가 있습니다(예:내부 조인, 외부 조인 및 하위 선택).이 접근 방식은 다음과 같은 여러 가지 이유로 문제가 됩니다.

  • 격리된 개별 규칙 단위 테스트 거의 불가능합니다
  • 마지막 요점은 또한 미래는 가장 확실히 위반 할 것입니다. 개방 폐쇄 원칙.
  • 비즈니스 논리와 지속성 문제가 혼합되고 있습니다.
  • 실제 데이터베이스가 필요하기 때문에 단위 테스트 실행 속도가 느림(SQLLite는 T-SQL을 구문 분석할 수 없으며 구문 분석기를 모의하는 것은 어어...어렵습니다)

저는 쿼리 성능을 매우 빠르게 유지하면서 유연하고 유지 관리 및 테스트가 가능한 대체 디자인을 찾으려고 노력하고 있습니다.OOAD 기반 구현이 적어도 일부 데이터 필터링 로직을 데이터베이스 서버에서 (.NET) 애플리케이션 서버로 이동할 것이라고 생각하기 때문에 이 마지막 점이 핵심입니다.

저는 명령과 책임 사슬 패턴의 조합을 고려하고 있습니다.

Query 클래스에는 추상 Rule 클래스(DateRule, TextRule 등) 컬렉션이 포함되어 있습니다.필터링되지 않은 데이터 집합을 포함하는 DataSet 클래스에 대한 참조를 보유합니다.DataSet은 지속성에 구애받지 않는 방식으로 모델링됩니다(즉, 데이터베이스 유형에 대한 참조나 후크가 없음).

Rule에는 DataSet을 가져와 적절하게 필터링한 다음 호출자에게 반환하는 단일 Filter() 메서드가 있습니다.Query 클래스는 단순히 각 규칙을 반복하여 각 규칙이 적절하다고 판단되는 대로 DataSet을 필터링할 수 있도록 합니다.모든 규칙이 실행되거나 DataSet이 아무것도 필터링되지 않으면 실행이 중지됩니다.

이 접근 방식에 대해 제가 걱정하는 한 가지는 .NET에서 잠재적으로 큰 필터링되지 않은 데이터 세트를 구문 분석할 때 성능에 미치는 영향입니다.유지 관리성과 성능 간의 적절한 균형을 제공하는 이러한 종류의 문제를 해결하기 위해 시도되고 진정한 접근 방식이 확실히 있습니까?

마지막 참고사항:관리에서는 NHibernate의 사용을 허용하지 않습니다.Linq에서 SQL로 변환하는 것이 가능할 수도 있지만 해당 기술이 현재 작업에 얼마나 적용될 수 있는지 잘 모르겠습니다.

많은 감사를 드립니다. 모든 분들의 피드백을 기다리겠습니다!

업데이트:아직도 이에 대한 해결책을 찾고 있습니다.

도움이 되었습니까?

해결책

LINQ에서 SQL이 VS2008 샘플의 동적 LINQ와 함께 이상적인 솔루션이 될 것이라고 생각합니다. LINQ, 특히 ienumerable/iqueryable의 확장 메소드를 사용하여 얻을 수있는 입력에 따라 표준 및 사용자 정의 논리를 사용하여 쿼리를 구축 할 수 있습니다. 이 기술을 크게 사용하여 많은 MVC 작업에 대한 필터를 구현하여 큰 효과를냅니다. 실제로 표현식 트리를 빌드 한 다음 쿼리를 구체화 해야하는 지점에서 SQL을 생성하는 데 사용하므로 대부분의 무거운 리프팅이 여전히 SQL 서버에 의해 수행되므로 시나리오에 이상적이라고 생각합니다. LINQ가 최적화되지 않은 쿼리를 생성하는 것으로 입증 된 경우, 최적화 된 쿼리를 활용하는 방법으로 LINQ 데이터 컨텍스트에 추가 된 테이블 값 기능 또는 저장 프로 시저를 항상 사용할 수 있습니다.

업데이트되었습니다: 당신은 또한 사용해 볼 수도 있습니다 술어 빌더 간단히 말해서 C# 3.0에서.

예 : 제목에 검색어 세트 중 하나가 포함되어 있고 게시자가 O'Reilly 인 모든 책을 찾으십시오.

 var predicate = PredicateBuilder.True<Book>();
 predicate = predicate.And( b => b.Publisher == "O'Reilly" );
 var titlePredicate = PredicateBuilder.False<Book>();
 foreach (var term in searchTerms)
 {
     titlePredicate = titlePredicate.Or( b => b.Title.Contains( term ) );
 }
 predicate = predicate.And( titlePredicate );

 var books = dc.Book.Where( predicate );

다른 팁

내가 본 방법은 사용자가 쿼리를 작성하기를 원하는 각 조건을 모델링하는 개체를 만들고 이를 사용하여 개체 트리를 구축하는 것입니다.

개체 트리에서 쿼리를 만족하는 SQL 문을 반복적으로 작성할 수 있어야 합니다.

필요한 기본 항목은 AND 및 OR 개체뿐만 아니라 EQUALS, LESSTHAN 등과 같은 모델 비교를 위한 개체입니다.아마도 이러한 객체에 대한 인터페이스를 사용하여 다양한 방법으로 더 쉽게 연결할 수 있을 것입니다.

간단한 예:

public interface IQueryItem
{
    public String GenerateSQL();
}


public class AndQueryItem : IQueryItem
{
    private IQueryItem _FirstItem;
    private IQueryItem _SecondItem;

    // Properties and the like

    public String GenerateSQL()
    {
        StringBuilder builder = new StringBuilder();
        builder.Append(_FirstItem.GenerateSQL());
        builder.Append(" AND ");
        builder.Append(_SecondItem.GenerateSQL());

        return builder.ToString();
    }
}

이런 방식으로 구현하면 규칙을 매우 쉽게 단위 테스트할 수 있습니다.

부정적인 측면에서는 이 솔루션이 여전히 많은 작업을 데이터베이스에 남겨두기 때문에 실제로는 원하지 않는 것처럼 들립니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top