4

我正在使用带有代码优先方法的 Entity Framework 5。

我有两个彼此具有多对多关系的类,Movie并且Person. A通过 aMovie与 a 相关。每个都可以有多个字符。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可以有一个Person播放多个Character。在这种情况下尝试添加时遇到问题Movie...

假设 Movie1 有 2 个角色都由 Person1 扮演。保存更改时,EF 将从 Character1 开始,并看到数据库中不存在 Person1 并将其插入Persondbo.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 个字符发送同一个人对象?它是否已经有一个唯一的密钥集?否则它们将被实体框架视为两个独立的对象。如果您已经定义了唯一键,则可以先检查 Local 集合,然后检查上下文,或者将人员添加到上下文中。

// 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 个单独的操作。如果您单独管理人员(这样一个人可以有零个或多个字符),这将是有意义的。

这会更有意义,因为电影不“拥有”人,这是多对多的关系。

例如在 UI 中:添加带有角色的电影时,您可以选择扮演角色的人,或者此时添加一个新角色。因此,当发送要保存的电影时,您将始终拥有一个 character.PersonId,它将指向已保存的人员对象。

当然,这可能不适用于您的特定场景,只是一个想法。

于 2012-12-17T06:27:46.447 回答
0

如果我正确理解了这个问题,这只发生在:

  1. 该人以前不存在于数据库中
  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 回答