5

を変換しようとしてIEnumerable<IEnumerable<string>>ICollection<Character>ますが、あるオブジェクトの構造が他のオブジェクトの構造と異なるため、正しい方法を見つけるのに苦労しています。

変換の理由は、json の逆シリアル化を取得し、それを Entity Framework を介してデータベースに挿入することです。json データは正規化されておらず、データベースの正確な構造と一致しません。データベースには、多対多の関係にあるamovieと aがあります。personそれらの間のブリッジ テーブルは ですcharacters。しかし、json には、人物オブジェクトの配列を持つ映画オブジェクトと、演じるキャラクターの配列を持つ各人物 ( IEnumerable<IEnumerable<string>>) しかありません。

基本的に、各映画の人物とその登場人物を、各映画の登場人物とそれぞれの人物に変換する必要があります。

var movie = dataContractMovies.Select(m => new Movie {
    Title = m.Title,
    // not sure how to convert each Person and their characters
    Characters = // Need to take each Person and their Characters in m.Cast and cast to a new Character and a new Person for which the Character belongs to
});

変換元

public class MovieDataContract {
    [DataMember(Name = "title")]
    public string Title { get; set; }

    [DataMember(Name = "abridged_cast")]
    public virtual IEnumerable<Person> Cast { get; set; }
}

[DataContract]
public class Person {
    [DataMember(Name = "name")]
    public string Name { get; set; }

    [DataMember(Name = "characters")]
    public IEnumerable<string> Characters { get; set; }
} 

に変換

public partial class Movie {
    public string Title { get; set; }
    public virtual ICollection<Character> Characters { get; set; }

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

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

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

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

更新と追加の質問

に を追加した場合はどうpublic IEnumerable<Character> CharactersなりMovieDataContractますか? 次に、このようなことを行うことができます(理論的には、テストしていません)...

Characters = m.Characters;

だから私の新しいMovieDataContractものはこのようになります...

[DataContract]
public class MovieDataContract {
    [DataMember(Name = "title")]
    public string Title { get; set; }

    [DataMember(Name = "abridged_cast")]
    private IEnumerable<Person> _cast { get; set; }

    public IEnumerable<Character> Characters { 
        get{  
            foreach(var person in _cast) {
                foreach(string name in person.characters) {
                    yield return new Character { Name = name, Person = new Person { Name = person.name }}
                }
            }
        } 
    }
}
4

2 に答える 2

2

私は答えのためにいくつかの仮定を立てています: 1. 新しい映画を挿入するだけで、既に DB にある映画を更新していません。2. Entity Framework を使用して挿入を行っています。3. 追加される映画の人物は、他の映画に関連付けられた DB にまだありません。4. すべての映画にはキャストがいて、すべてのキャスト メンバーには少なくとも 1 人のキャラクターがいます。

クールなキッズバスから放り出されるリスクがあるため、私のソリューションでは LINQ を使用していませんが、そうするように変更できると確信しています。EF では、関連付けをデータベースに挿入するために関連付けの両端を設定する必要がないことに注意してください。

// Lookup is necessary because a person might be in more than one movie.
var personLookup = new Dictionary<string,Person>();

foreach (var contractMovie in dataContractMovies)
{
    var movie = new Movie() { Title = contractMovie.Title };

    foreach (var contractPerson in contractMovie.Cast)
    {
        if (!personLookup.ContainsKey(contractPerson.Name))
        {
            personLookup.Add(contractPerson.Name, new Person() { Name = contractPerson.Name });
        }
        var person = personLookup[contractPerson.Name];

        foreach (var contractCharacter in contractPerson.Characters)
        {
            var character = new Character() { Name = contractCharacter.Name, Person = person, Movie = movie };

            dataContext.Characters.Add(character);
        }
    }
 }
 dataContext.SaveChanges();

DataContract が Movie を Person ではなく Character にマップした場合 (コメントで提案したように)、次のようなものでうまくいく可能性があります。

var personLookup = new Dictionary<string, Person>();
var movie = dataContractMovies.Select(m => new Movie {
    Title = m.Title,
    Characters = m.Characters.Select(c => new Character() { Name = c.Name, Person = LookupPerson(c.Person, personLookup) }).ToList()
});

public Person LookupPerson(string personName, Dictionary<string, Person> personLookup)
{
        if (!personLookup.ContainsKey(personName))
        {
            personLookup.Add(personName, new Person() { Name = personName });
        }
        return personLookup[personName];
}
于 2012-11-07T22:24:59.690 に答える
1
var flattenedShape =
  from movie in dataContractMovies
  from person in movie.Cast
  from characterName in person.Characters
  select new {Movie = movie, Person = person, CharacterName = characterName};


List<Character> characters = new List<Character>();
Dictionary<MovieDataContract, Movie> movieMap =
  new Dictionary<MovieDataContract, Movie>();
Dictionary<PersonDataContract, Person> personMap =
  new Dictionary<PersonDataContract, Person>();

foreach(var row in flattenedShape)
{
  //have I seen this movie yet?
  if (!movieMap.ContainsKey(row.Movie))
  {
    movieMap.Add(row.Movie, new Movie() { Title = row.Movie.Title });
  }

  //have I seen this person yet?
  if (!personMap.ContainsKey(row.Person))
  {
    personMap.Add(row.Person, new Person() { Name = row.Person.Name });
  }

  //every character is unique.
  Character x = new Character() { Name = row.CharacterName };
  movieMap.Characters.Add(x);
  x.Movie = movieMap[row.Movie];
  personMap.Characters.Add(x);
  x.Person = personMap[row.Person];
  characters.Add(x);
}

//at this point, all the characters are in characters...
// all the movies are in the movieMap.Values...
// and all the persons are in the personMap.Values
于 2012-11-07T21:15:43.050 に答える