在实体框架代码中添加多对多关系
我想在多个现有实体和另一个现有实体之间添加关系。这里是我的模型:在实体框架代码中添加多对多关系
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;
}
现在我想,当我拨打这个电话在我的业务层这会工作
不幸的是,这并没有得到更新,当我检查数据库时,中间表中没有任何内容。也没有例外。
在这种情况下使用AsNoTracking
是问题所在。没有AsNoTracking
它会工作。您必须记住,您只能使用更改跟踪机制更新多对多关系。但在您的代码中,当您在UpdateTerm
方法中调用Attach
时,EF上下文将首次知道term
和SubForms
集合。 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;
}
我只是删除了所有我得到的声明notracking。这会影响其他人可能编写的任何代码吗? –
@Lolcoder:当然,它会影响其他代码(性能,错误,如果加载的实体被连接到其他上下文,无论...)。我不会不小心做到这一点。如果您不确定此更改的影响,则最好使用与旧行为相对应的默认值创建新方法或参数。 – Slauma
可以使用同一个存储库来删除关系,或者我将不得不为此编写一个新的方法? –
我已经通过上述的一个简单的设置没有属性位,我在链接表中得到一个记录。你有没有使用你的设置属性位尝试? – WestDiscGolf
@WestDiscGolf我添加了代码来跳过属性的东西,如果它为空。它仍然没有为我创造。你使用db.Terms.Attach吗? –
我不使用任何跟踪来获取实体。 –