2

SQLには次のようなテーブルがあります:

PersonOrganisationRole

次の列があります。

PersonId, OrganisationId RoleId

つまり、人、組織、役割の間の 3 方向のテーブルです。

そのため、個人が属するすべての組織を取得する方法を作成したいと考えていました。

public class Person
{
  public IEnumerable<Organisation> Organisations
        {
            get 
            { 
                var organisations = new List<Organisation>();

                foreach (var personOrganisationRole in PersonOrganisationRoles.Where(personOrganisationRole => !organisations.Contains(personOrganisationRole.Organisation)))
                {
                    organisations.Add(personOrganisationRoles.Organisation);
                }

                return organisations;
            }
        }
}

したがって、基本的には、テーブル内のすべての項目を繰り返し処理し、組織をまだ追加していない場合にのみ組織を追加することで、リストを作成しています。個人が組織で複数の役割を持つ可能性があるため、同じ PersonId と OrganizationId を持つテーブルに複数の行が存在する可能性があるため、これは重要です。

このコードを書くためのはるかに良い方法があるはずですが、私は考えています。

助言がありますか?

4

4 に答える 4

2

LINQのDistinct演算子を使用して、この一意の収集を実行しToList、結果をリストに収集できます。

return PersonOrganisationRoles
    .Distinct(x => x.Organisation)
    .ToList();
于 2012-10-14T20:22:45.943 に答える
1
public IEnumerable<Organisation> Organisations
{
    get 
    { 
        return PersonOrganisationRoles
            .Select(por => por.Organisation)
            .Distinct()
            .ToList();
    }
}

組織が実装していることを確認する必要があります

  • GetHashcodeそしてEqualsきちんと
  • オプションで実装IEquatable<Organisation>

Distinct はこれらを使用して、アイテムが既にコレクションにあるかどうかを確認します。(Contains元のサンプルでも同じことをしたので、おそらくそれが意図したものです)

于 2012-10-14T20:19:44.810 に答える
0

Linq Select() と Distinct() メソッドの組み合わせでそれを行う必要があります。

 var organisations = PersonOrganisationRoles
              .Select<PersonOrganisationRoles,Organisation>(p => p.Organisation )
              .Distinct();
于 2012-10-14T20:48:06.603 に答える
0

プロパティではなく関数にします。

私たちは objectInstance.PropertyName の記述に慣れており、通常、これは既にメモリ内にあるデータの一部にアクセスする高速な操作だと考えています。あなたの場合、 Person.Organizations への呼び出しには、何らかの処理と、場合によっては IO 操作が含まれます。

もう 1 つの、おそらくより重要なポイントは、次の場合です。

var a = myPerson.Organizations;
var b = myPerson.Organizations;

a は、メモリ内の b と同じ List<> インスタンスを指していると思います。

そして、あなたのコードではそれは真実ではありません。したがって、処理が一度だけ行われるように、プロパティを関数に変更するか、結果をプライベート プロパティにキャッシュしてください。このような:

public class Person
{
  private IEnumerable<Organisation> organizations; 

  public IEnumerable<Organisation> Organisations
  {
    get 
    { 
       if (organizations != null) return organizations;

       organisations = new List<Organisation>();
       // fill list here 
       return organisations;
     }
  }
}
于 2012-10-14T20:30:27.073 に答える