2011-11-21 132 views
0

我想在多个现有实体和另一个现有实体之间添加关系。这里是我的模型:在实体框架代码中添加多对多关系

public class Term 
{ 
    public int TermId { get; set; } 
    public virtual ICollection<SubForm> SubForms { get; set; } 
} 

public class SubForm 
{ 
    public int SubFormId { get; set; } 
    public virtual ICollection<Term> Terms { get; set; } 
} 

我有一个更新存储库的方法如下:

public void AddFormToTerm(int termId, int formId) 
{ 
    var term = termsRepository.GetTerms().FirstOrDefault(t => t.TermId == termId); 
    var subForms = termsRepository.GetSubForms().Where(t => t.FormId == formId); 

    //I assume this would work by adding existing forms to an existing term. 
    foreach (var subForm in subForms) 
    { 
     term.SubForms.Add(subForm); 
    } 

    termsRepository.UpdateTerm(term, null); 
} 

public IQueryable<Term> GetTerms() 
{ 
    IQueryable<Term> query = db.Terms.AsNoTracking(); 
    return query; 
} 

public Term UpdateTerm(Term term, IEnumerable<Expression<Func<Term, object>>> properties) 
{ 
    if (term.TermId == 0) 
    { 
     throw new InvalidOperationException("Term does not exist"); 
    } 
    db.Terms.Attach(term); 
    if (properties != null) 
    { 
     foreach (var selector in properties) 
     { 
      string propertyName = Helpers.PropertyToString(selector.Body); 
      db.Entry(term).Property(propertyName).IsModified = true; 
     } 
    } 
    db.SaveChanges(); 
    return term; 
} 

现在我想,当我拨打这个电话在我的业务层这会工作

不幸的是,这并没有得到更新,当我检查数据库时,中间表中没有任何内容。也没有例外。

+0

我已经通过上述的一个简单的设置没有属性位,我在链接表中得到一个记录。你有没有使用你的设置属性位尝试? – WestDiscGolf

+0

@WestDiscGolf我添加了代码来跳过属性的东西,如果它为空。它仍然没有为我创造。你使用db.Terms.Attach吗? –

+0

我不使用任何跟踪来获取实体。 –

回答

1

在这种情况下使用AsNoTracking是问题所在。没有AsNoTracking它会工作。您必须记住,您只能使用更改跟踪机制更新多对多关系。但在您的代码中,当您在UpdateTerm方法中调用Attach时,EF上下文将首次知道termSubForms集合。 EF没有注意到您确实已将SubForms添加到term,因为这些实体未附加到上下文(因为您使用了AsNoTracking =“EF,请不要附加到上下文!”)。但在Attach之后,在调用SaveChanges之前什么也没有发生=没有变化=没有数据库命令。 因此删除AsNoTracking(或创建另一个方法或参数加载跟踪)是最好的选择。一切都会涉及这样丑陋的“技巧”:

public Term UpdateTerm(Term term, ...) 
{ 
    //... 

    // Restore the state before adding the subforms = current state in DB 
    var tempSubForms = term.SubForms; 
    term.SubForms = null; 

    // Inform EF about this state = term exists, subforms exist 
    // in DB but no relationships 
    db.Terms.Attach(term); 
    foreach (var subForm in tempSubForms) 
     db.SubForms.Attach(subForm); 

    // Change the state: EF change tracking recognizes this 
    term.SubForms = tempSubForms; 

    //... 

    // EF now will send INSERT statements for the join table 
    db.SaveChanges(); 
    return term; 
} 
+0

我只是删除了所有我得到的声明notracking。这会影响其他人可能编写的任何代码吗? –

+0

@Lolcoder:当然,它会影响其他代码(性能,错误,如果加载的实体被连接到其他上下文,无论...)。我不会不小心做到这一点。如果您不确定此更改的影响,则最好使用与旧行为相对应的默认值创建新方法或参数。 – Slauma

+0

可以使用同一个存储库来删除关系,或者我将不得不为此编写一个新的方法? –