복붙노트

[SQL] 자 NHibernate은 - 많은 쿼리에 많은 정션 / 목공 테이블을 사용하여

SQL

자 NHibernate은 - 많은 쿼리에 많은 정션 / 목공 테이블을 사용하여

여기 매우 비슷한 질문을 찾았지만 경기는 정확히 내가 무엇을 찾고 있어요 없음있다. 내가 찾은 두 가장 가까운 스레드 (예, 서로 다른 스레드입니다)입니다 :

NHibernate에 대다 기준 (1)

NHibernate에 대다 기준 (2)

그러나, 나는 직접 대다 관계를 사용하는 사람들의 모두를 생각한다. 사실은 꽤 표준 방법입니다 접합 테이블, 두 개의 일대 다 관계를 가진하여 다 대다 관계를 시뮬레이션하고 있습니다. 여기 내 NHibernate에 매핑은 다음과 같습니다 :

파일 :

<class name="Files" table="files">
  <id name="id">
    <generator class="identity" />
  </id>
  <property name="name" />

  <bag name="files_attrs" table="files_attrs" lazy="true">
    <key column="file_id" />
    <one-to-many class="Files_Attrs" />
  </bag>
</class>

속성 :

<class name="Attrs" table="attrs">
  <id name="id">
    <generator class="identity" />
  </id>
  <property name="name" />
  <property name="value" />

  <bag name="files_attrs" table="files_attrs" lazy="true">
    <key column="attr_id" />
    <one-to-many class="Files_Attrs" />
  </bag>
</class>

목공 :

<class name="Files_Attrs" table="files_attrs">
  <id name ="id">
    <generator class="identity" />
  </id>
  <many-to-one name="file" cascade="all" column="file_id" />
  <many-to-one name="attr" cascade="all" column="attr_id" />
</class>

그래서 내 문제는 바로 위의 두 번째 링크 유사하지만 분기점 표와 다. 그래서:

속성 ID의 집합을 감안할 때, 나는 나에게 그 일치하는 속성을 모두 가지고있는 파일을 제공하는 쿼리를 실행 바라고 있어요. 나는 쉽게 세트의 각 속성 ID의 "N"쿼리를 실행하고 모든 목록에 표시 파일 ID에 대한 각 목록을 비교하지만, 하나 개의 쿼리를 한 번에이 모든 것을 할 수있는 쉬운 방법이 있어야 같은 느낌 할 수 있습니다.

예:

File      | Attributes
----------+-----------------------------------------------------
foo.txt   | (mode = read-only,                    view = visible)
bar.txt   | (mode = read-write, security = all,   view = visible)
duck.txt  | (mode = read-only,                    view = hidden)
goose.txt | (more = read-only,  security = owner, view = visible)

이러한 특성을 감안할 때 : 모드 = 읽기 전용 뷰를 볼 수 =, 난 단지에 foo.txt 및 goose.txt 반환하고자합니다.

이와 캔 사람의 도움 나? 감사.

해결법

  1. ==============================

    1.많은 서브 쿼리가 합류하고 많은 속성을 찾을 수 있어야합니다으로이를 달성하는 방법을 한 가지 방법은, 만들 수 / 파일을 검색 관련

    많은 서브 쿼리가 합류하고 많은 속성을 찾을 수 있어야합니다으로이를 달성하는 방법을 한 가지 방법은, 만들 수 / 파일을 검색 관련

    첫번째 방법은 상위 계층으로부터 상기 이름 / 값 쌍으로 작동한다. 즉 사용자가 선택한 모드는 읽기 전용 수 (두 번째는 우리가 이미 ID 년대가 Atttributes을 검색의가 있음을 예상하고, 좀 더 쉽게 될 것입니다)

    // Below I am using C# properties, which I guess are correct
    // based on the mapping. Naming convention is more Java (camel)
    // but this should work with above mapping 
    // (also - class name Contact, not File)
    
    Files file = null; // this is an alias used below
    
    // here the attributes collection represents search filter
    // ... settings for which is user looking for
    var attributes = new List<Attrs>
    {
        new Attrs{ name = "mode", value = "read-only" },
        new Attrs{ name = "view", value = "visible" }
    };
    
    // Let's start with definition of the outer/top query
    // which will return all files, which do meet all filter requirements
    var query = session.QueryOver<Files>(() => file);
    

    다음 단계에서, 우리는, 즉 컬렉션 필터 속성을 반복합니다

    // here we will take each attribute and create a subquery
    // all these subqueries, will be joined with AND
    // so only these files, which do have all attributes, will be selected
    foreach (var attr in attributes)
    {
        // create the subquery, returning the FileId
        Attrs attribute = null;
        var subQueryForAttribute = QueryOver.Of<Files_Attrs>()
                .JoinQueryOver(fa => fa.attr, () => attribute)
                .Select(x => x.file.id)
                ;
    
        // now, take name and value
        var name = attr.name;
        var value = attr.value;
    
        // and convert them into where condition
        subQueryForAttribute.Where(() => attribute.name == name);
        subQueryForAttribute.Where(() => attribute.value == value);
    
        // finally, add this subquery as a restriction to the top level query
        query.WithSubquery
            .WhereProperty(() => file.id)
            .In(subQueryForAttribute);
    }
    

    우리는 파일의 평면 구조 작업을하기 때문에 - 이제 우리는 지원 페이징에 대한 준비가 쿼리를 보유하고 있습니다. 우리가 테이크를 사용하고 필요한 경우 건너 뛸 수 있도록 검색 파일의 목록을

    // query.Take(25);
    // query.Skip(100);
    
    var list = query.List<Files>();
    

    이것은이 같은 SELECT가 발생합니다 쿼리입니다

    SELECT ...
    FROM files
    WHERE id IN (SELECT file_Id FROM files_attrs 
                                  INNER JOIN attrs ON attrs.id = file_attrs.attr_id
                                WHERE name = 'mode' AND value = 'read-only' )
      AND id IN (SELECT file_Id FROM files_attrs 
                                  INNER JOIN attrs ON attrs.id = file_attrs.attr_id
                                WHERE name = 'view' AND value = 'visible' )
    

    두 번째 솔루션은 쉽게 시작하는 대신 속성의 조건 (이름과 값) 우리는 이미 자신의 ID를 (질문에서 인용이있다 :

    // Below I am using C# properties, which I guess are correct
    // based on the mapping. Naming convention is more Java (camel)
    // but this should work with above mapping 
    // (also - class name Files, not File)
    
    Files file = null; // this is an alias used below
    
    // here the attributeIds collection represents attributes to be found
    var attributeIds = new List<int> { 1, 4, 5 };
    
    // Let's again start with definition of the outer/top query
    // which will return all files, which do meet all filter requirements
    var query = session.QueryOver<Files>(() => file);
    

    다음 관계로서 존재해야 알려진 ID들의 세트를 통해 반복 (모두) 인

    // here we will take each attribute and create a subquery
    // all these subqueries, will be joined with AND
    // so only these files, which do have all attributes, will be selected
    foreach (var attrId in attributeIds)
    {
        // create the subquery, returning the Files.id
        var subQueryForAttribute = QueryOver.Of<Files_Attrs>()
                // no need to join, all the stuff is in the pairing table
                .Select(x => x.file.id)
                ;
        var id = attrId; // local variable
        // and convert them into where condition
        subQueryForAttribute.Where(pair => pair.attr.id == id);
    
        // finally, add this subquery as a restriction to the top level query
        query.WithSubquery
            .WhereProperty(() => file.id)
            .In(subQueryForAttribute);
    }
    
    var list = query.List<Files>();
    

    알려진 IDS와 해결책은 (작은 테이블이 SQL 문에 필요) 조금 더 쉽게

    참고 : 말을 : 당신이 도입 한 것으로, 그것을보고 큰 인 대일 및 일대 대신 대다. 나는 개인적으로,이 정확히이 예제 쇼를 말할 것, 그것이 가져올 수있는 방법 큰 이익 ... 능력은 복잡한 필터를 검색합니다

    일부 링크는 QueryOver의 힘을 보여주기 위해 : 다 대다 여분의 열이 NHibernate에 : hasMany의 기준에 대한 질의 및 좋은 이유는 왜 many-to-many 매핑을 사용하지

  2. ==============================

    2.임이 당신이 필요 확실하지 경우 :

    임이 당신이 필요 확실하지 경우 :

    <bag name="files_attrs" table="files_attrs" lazy="true" where="something like '%mode = read-only%' and something like '%view = visible%'">
        <key column="attr_id" />
        <one-to-many class="Files_Attrs" />
    </bag>
    

    뭔가 속성 또는 필터 데이터입니다 열이입니다.

  3. from https://stackoverflow.com/questions/23772548/nhibernate-many-to-many-query-using-junction-joiner-table by cc-by-sa and MIT license