有没有办法强制实体框架在将实体添加到上下文时立即填充外键,而不是将其推迟到上下文发生其他情况?使用数据绑定显示引用的实体时,此默认行为不是很有用。
只需引用上下文中的任何DbSet
即可强制EF填充已添加的Parent
的{{1}}和Parent_Name
。但是,Children
似乎迫使EF填充SaveChanges
或Reference
。
我真的很想用Reference_Name
ttribute标记Reference_Name
,因此它在数据库中会[Required]
,但如果我这样做,那么当我这样做时,我会收到验证错误尝试拨打Not Null
,除非我已明确设置SaveChanges
,即使设置了参考,Reference_Name
本身也会正确填充SaveChanges
。
我真的希望能够设置Reference_Name
或Reference
并能够立即使用另一个。同样,我希望能够在添加Reference_Name
对象后立即使用Parent
或Parent_Name
,而无需先使用从上下文中访问其他元素的kludge
任何人都可以帮助我理解为什么EF会延迟这些事情,以及我如何强制它填充外键属性或外键列,最好是立即但至少不必调用Child
?当EF要正确填充它们时,我真的不想完全填充所有属性。
SaveChanges
答案 0 :(得分:2)
有没有办法强制Entity Framework在将实体添加到上下文时立即填充外键,而不是在上下文发生其他事件之前将其延迟?
选项1:
如果您只想修复实体之间的关系,而不将其保存到数据库,因此调用DbContext.SaveChanges()
,然后只需调用DbContext.ChangeTracker.DetectChanges()
。
选项2:
EF可以自动修复entites之间的关系,而无需调用DbContext.SaveChanges()
或DbContext.ChangeTracker.DetectChanges()
。这些entites称为代理类。代理类是动态生成的派生类型,充当实体的代理。此代理会覆盖实体的某些虚拟属性,以插入用于在访问属性时自动执行操作的挂钩。默认情况下会为DbContext
启用代理创建,除非您通过调用DbContext.Configuration.ProxyEnabled = false;
将其停用。您不需要添加该行代码,因为您需要启用代理创建。
无论如何,在使用此功能之前,您需要修改课程中的一些内容:
ICollection<T>
DbContext.DbSet<T>.Create()
方法完成。按照这些步骤,您的entites类必须如下所示:
public class Parent
{
[Key, MaxLength(30)]
public virtual string Name { get; set; }
[InverseProperty("Parent")]
public virtual ICollection<Child> Children { get; set; }
}
public class Child
{
[Key, Column(Order = 1), MaxLength(30)]
public virtual string Parent_Name { get; set; }
[Key, Column(Order = 2), MaxLength(30)]
public virtual string Name { get; set; }
public virtual string Reference_Name { get; set; }
[ForeignKey("Parent_Name")]
public virtual Parent Parent { get; set; }
[ForeignKey("Reference_Name")]
public virtual Reference Reference { get; set; }
public Child Clone()
{
return new Child
{
Parent_Name = this.Parent_Name,
Name = this.Name,
Reference_Name = this.Reference_Name,
Parent = this.Parent,
Reference = this.Reference
};
}
}
public class Reference
{
[Key, MaxLength(30)]
public virtual string Name { get; set; }
}
public class SomethingElse
{
[Key, MaxLength(30)]
public virtual string Name { get; set; }
}
您的点击事件处理程序impelmentation将如下所示:
Reference reference = context.References.Create();
reference.Name = "Reference";
context.References.Add(reference);
Parent alpha = context.Parents.Create();
alpha.Name = "Alpha";
context.Parents.Add(alpha);
Child alphaOne = context.Children.Create();
alphaOne.Name = "AlphaOne";
Child alphatwo = context.Children.Create();
alphatwo.Name = "AlphaTwo";
alphatwo.Reference = reference; // Notice we use the navigational property.
alpha.Children.Add(alphaOne);
alpha.Children.Add(alphatwo);
alphaOne.Reference = reference;
var list = (
from child in alpha.Children
select new
{
Time = "Before referencing SomethingElses.Local",
Child = child.Clone()
}
).ToList();
var x = context.SomethingElses.Local;
list.AddRange(
from child in alpha.Children
select new
{
Time = "After referencing SomethingElses.Local",
Child = child.Clone()
}
);
list.AddRange(
from parent in context.Parents.Local
from child in parent.Children
select new
{
Time = "Before SaveChanges",
Child = child.Clone()
}
);
context.SaveChanges();
list.AddRange(
from parent in context.Parents.Local
from child in parent.Children
select new
{
Time = "After SaveChanges",
Child = child.Clone()
}
);
foreach (var item in list)
{
Console.WriteLine("{0}:\r\n\tName = '{1}'\r\n\tParent = '{2}' ({3})\r\n\tReference = '{4}' ({5})",
item.Time, item.Child.Name, item.Child.Parent_Name, item.Child.Parent, item.Child.Reference_Name, item.Child.Reference);
}
此实施中有两个明显的变化:
Reference_Name = "Reference"
将无法帮助您的上下文延迟加载导航属性Refererence
。这就是为什么而不是alphatwo.Reference_Name = "Reference";
我执行alphatwo.Reference = reference;
因为reference
处于Added
状态,而Lazy Load将在数据库中找不到任何内容。