4

コードファーストアプローチでEntityFramework5を使用しています。

互いに多対多の関係にある2つのクラスがMovieありPersonます。Aは経由Movieでに関連付けられています。それぞれに複数の文字を含めることができます。PersonCharacterMovie

public class Movie {
    public int Id { get; set; }
    public string Title { get; set; }
    public int? Year { get; set; }
    public virtual ICollection<Character> Characters { get; set; } 

    public Movie() {
        Characters = new HashSet<Character>();
    }
}

public class Character {
    public string Name { get; set; }    
    public virtual Movie Movie { get; set; }    
    public virtual Person Person { get; set; }
}

public class Person {
    public int Id { get;set; }
    public string Name { get; set; }
    public virtual ICollection<Character> Characters { get; set; }

    public Person() {
        Characters = new HashSet<Character>();
    }
}

場合によっては、複数のを再生するMovieものを使用できます。この状況でアンダーを追加しようとすると、問題が発生します...PersonCharacterMovie

Movie1に2人のキャラクターがいて、両方ともPerson1が演じているとしましょう。変更を保存すると、EFはCharacter1から開始し、Person1がデータベースに存在しないことを確認し、それをに挿入しPersonますdbo.Person。次に、Character2に移動しますが、Person1がすでに存在し、主キー違反をスローすることを確認します。

MovieRepositoryにはAdd(Movie entity)方法があります。CharacterそれぞれをループしてMovie、関連するものがデータベースに存在するかどうかを確認しPersonます。もしそうなら、私はPersonプロパティを既存のに設定しますPerson。これは通常の場合に機能しますが、Personがまったく存在しない場合は、PK違反を回避する方法がわかりません。これが私の問題です:)

public class MovieRepository : Repository<Movie> {
    public MovieRepository(MovieContext context) : base(context) {}

    public override void Add(Movie entity) {
        foreach (var character in entity.Characters) {
            var person = Context.People.FirstOrDefault(p => p.Id == character.Person.Id);
            if (person != null)
                character.Person = person;
        }
        Context.Movies.Add(entity);
    }
}

もう少し情報を追加するだけです。リポジトリとコンテキストを保持するために、作業ユニットパターンでリポジトリパターンを使用しています。したがって、UnitOfWorkクラスはを担当しSaveChanges()ます。

でこれを実行しようとすると、MovieRepository.Add()このタスクを実行するための最良/適切な方法ではない場合があります。私はありとあらゆる提案を楽しみにしています。

さらに明確にするために、Rotten Tomatoes APIからデータを取得していますが、jsonは次のようになっています...

{data : [{
    Id: 12345,
    Title: 'Movie1',
    Year: 2010,
    Character: [{
        Name: 'Character1',
        Person: { Id: 1, Name: 'Person1' }
    },{
        Name: 'Character2',
        Person: { Id: 2, Name: 'Person2' }
    }]
}]}
4

2 に答える 2

3

同じ人物のオブジェクトを2文字でどのように送信しますか?すでに一意のキーセットがありますか?それ以外の場合は、EntityFrameworkによって2つの別個のオブジェクトとして表示されます。一意のキーがすでに定義されている場合は、最初にローカルコレクションを確認してからコンテキストを確認するか、ユーザーをコンテキストに追加します。

// Only works if the unique key is already defined.
var person =
    Context.People.Local.FirstOrDefault(p => p.Id == character.Person.Id) ??
    Context.People.FirstOrDefault(p => p.Id == character.Person.Id);

if (person == null)
    Context.People.Add(person);

ただし、この方法で人がまったく追加されないように、集計を変更することをお勧めします。人の追加と「映画」の追加({Movie、Character}の集合体として2つの別々の操作として扱うことができます。これは、人を別々に管理する場合(人が0個または多数の文字を持つことができるように)に意味があります)。

映画は人々を「所有」していないので、これはより理にかなっています。それは多対多の関係です。

たとえば、UIの場合:キャラクターを含む映画を追加する場合、キャラクターを演じた人を選択するか、この時点で新しい人を追加します。したがって、保存するムービーを送信するときは、常にcharacter.PersonIdがあり、これはすでに保存されている人物オブジェクトを指します。

もちろん、これは特定のシナリオでは機能しない場合がありますが、単なるアイデアです。

于 2012-12-17T06:27:46.447 に答える
0

問題を正しく理解している場合、これは次の場合にのみ発生します。

  1. その人は以前はDBに存在していませんでした
  2. その人は映画で複数のキャラクターを演じていますか?

より明確に言えば、DBにすでに存在する人物が映画で2人のキャラクターを演じた場合、同じ失敗がありますか?

2回目に使用する前に、新しい人を永続化(保存)する必要があるように思われますか?

何かのようなもの:

public class MovieRepository : Repository<Movie> {
public MovieRepository(MovieContext context) : base(context) {}

public override void Add(Movie entity) {
    foreach (var character in entity.Characters) {
        var person = Context.People.FirstOrDefault(p => p.Id == character.Person.Id);
        if (person != null) {
            character.Person = person;
        } else {
            personRepository.Save(character.Person)
        }
    }
    Context.Movies.Add(entity);
}
于 2012-12-14T23:20:50.047 に答える