c# - 从 IEnumerable<IEnumerable<string>> 转换为 ICollection<T>

标签 c# linq entity-framework casting

我正在尝试转换 IEnumerable<IEnumerable<string>>ICollection<Character>但由于一个对象的结构与另一个对象的结构不同,因此很难找出正确的方法。

转换的原因是进行 json 反序列化并通过 Entity Framework 将其插入到数据库中。 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>();
    }
}

更新和进一步的问题

如果我只添加一个 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 }}
                }
            }
        } 
    }
}

最佳答案

我对我的回答做了一些假设:1. 我们只插入新电影,而不是更新数据库中已有的电影。 2. 我们正在使用 Entity Framework 来进行插入。 3. 正在添加的电影中的人物不在与其他电影关联的数据库中。 4. 每部电影都有一个 Actor ,每个 Actor 至少有一个角色。

冒着被赶下酷 child 巴士的风险,我的解决方案没有使用 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 映射到 Character 而不是 Person(就像您在评论中建议的那样),您可能会得到更像这样的东西:

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

关于c# - 从 IEnumerable<IEnumerable<string>> 转换为 ICollection<T>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13276806/

相关文章:

c# - 如何使用 C# 比较两个列表?

c# - 对可为空值的多个可能组合执行 Linq 操作

c# - 在 .getJSON 中传递数据。可能的?如何?

linq - 最有效的 Entity Framework 代码优先方法,用于展平/投影具有特定子实体的父实体

c# - 可感知时间/更新的集合的枚举器

c# - 基于 Odata Controller 中的 ImageKey 将图像加载到 igGrid 列中

entity-framework - HasKey Throwing InvalidOperationException-这是Entity Framework Code First中的错误吗?

c# - 主题 + 动态控件创建 + 不可见的 UserControl = View 状态错误?

c# - 为什么 Visual Studio 不警告我空引用异常?

c# - 在控制台应用程序中调用 HttpClient.GetAsync - 死锁