2012-11-07 102 views
5

我想一個IEnumerable<IEnumerable<string>>轉換爲ICollection<Character>,但努力找出要做正確的方式,因爲一個對象的結構比其他的結構不同。自IEnumerable <IEnumerable的<string>>轉換爲ICollection的<T>

轉換的原因是採取JSON反序列化並通過實體框架將其插入到數據庫中。 json數據沒有標準化,並且與數據庫的確切結構不匹配。在數據庫中,我有一個movie和一個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>(); 
    } 
} 

更新和進一步的問題

什t如果我只是在MovieDataContract上加了public IEnumerable<Character> Characters?然後,我可以做這樣的事情(在理論上,沒有測試)...

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 }} 
       } 
      } 
     } 
    } 
} 
+0

你打算如何從'串去'去'Character'?如果沒有將僞值對象轉換爲引用對象的好方法,找出包裝問題並不會對您有太大的幫助。 – tmesser

+3

它看起來像* bflemi3 *想要將樹結構(由Web服務返回)轉換爲關係結構(要使用實體框架插入到數據庫中)。 IEnumerable >東西是一個紅色的鯡魚。 – dtb

+0

@ bflemi3:如果您可以添加示例,這將有所幫助。 – dtb

回答

2

我我爲我的答案做了一些假設:1.我們只插入新電影,而不更新數據庫中已有的電影。 2.我們使用實體框架來進行插入。 3.正在添加的電影中的人不在與其他電影關聯的數據庫中。 4.每部電影都有劇組,每個劇組成員至少有一個角色。

冒着風險擺脫涼爽的孩子巴士我的解決方案不使用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映射電影到字符,而不是人(就像你在你的意見建議),你可以有更多的東西像這樣的僥倖:

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]; 
} 
+0

謝謝,這很有趣,它給了我一個主意。如果我將「MovieDataContract」更改爲具有可返回「IEnumerable 」的屬性,該怎麼辦?那麼我只需要引用'm.Characters'? – bflemi3

+0

我同意上面的David B的評論。當DataContract對象進入每個項目時都會有它自己的唯一實例。因此,如果您與哈里森福特有兩部電影,那麼將會有兩個數據合約人物對象,名稱爲哈里森福特。如果將這些元素轉換爲實體對象1,那麼您最終會得到兩個哈里森福特人實體,並且當您嘗試將其保存到數據庫時會得到重複。 – MichaC

+0

如果您對MovieDataContract進行了建議更改,我更新了我的答案,使其更接近您最初嘗試的內容。 – MichaC

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 
+0

謝謝,這很有趣,它給了我一個主意。如果我將「MovieDataContract」更改爲具有可返回「IEnumerable 」的屬性,該怎麼辦?那麼我只需要引用'm.Characters'? – bflemi3

+0

只要不在電影之間共享人員,該屬性就是好的。 –

相關問題