Mat*_*les 5 c# entity-framework
当实体添加到上下文时,是否有任何方法可以强制实体框架立即填充外键,而不是延迟它直到上下文发生其他情况?当使用数据绑定显示引用的实体时,此默认行为不是很有帮助。
DbSet只需引用上下文中的any就足以强制 EFParent填充Parent_Name添加的Children. 但似乎没有什么比SaveChanges强制 EF 填充Referenceor 更重要Reference_Name了。
我真的很想Reference_Name用[Required]ttribute 进行标记,这样它将Not Null在数据库中,但如果我这样做,当我尝试调用时,SaveChanges除非我显式设置了,否则我会收到验证错误Reference_Name,即使如果 Reference 是,SaveChanges它本身也会正确填充Reference_Name放。
我真的希望能够设置其中一个Reference或Reference_Name并能够立即使用另一个。同样,我希望能够立即使用Parent或Parent_Name添加Child对象后,而不必首先从上下文中访问其他元素。
谁能帮助我理解为什么 EF 会延迟这些事情,以及如何强制它填充外键属性或外键列,最好是立即填充,但至少不必调用SaveChanges?当 EF 无论如何要正确填充它们时,我真的不想显式地完全填充所有属性。
public class OracleContext : DbContext
{
public virtual DbSet<Parent> Parents { get; set; }
public virtual DbSet<Child> Children { get; set; }
public virtual DbSet<Reference> References { get; set; }
public virtual DbSet<SomethingElse> SomethingElses { get; set; }
}
public class Parent
{
[Key, MaxLength(30)]
public string Name { get; set; }
[InverseProperty("Parent")]
public virtual List<Child> Children { get; set; } = new List<Child>();
}
public class Child
{
[Key, Column(Order = 1), MaxLength(30)]
public string Parent_Name { get; set; }
[Key, Column(Order = 2), MaxLength(30)]
public string Name { get; set; }
public 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 string Name { get; set; }
}
public class SomethingElse
{
[Key, MaxLength(30)]
public string Name { get; set; }
}
private void button1_Click(object sender, EventArgs e)
{
OracleContext context = new OracleContext();
Reference reference = context.References.Add(new Reference { Name = "Reference" });
Parent alpha = context.Parents.Add(new Parent { Name = "Alpha" });
Child alphaOne = new Child { Name = "AlphaOne" };
Child alphatwo = new Child { Name = "AlphaTwo", Reference_Name = "Reference" };
alpha.Children.AddRange(new List<Child> { alphaOne, 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);
}
}
Before referencing SomethingElses.Local:
Name = 'AlphaOne'
Parent = '' ()
Reference = '' (WindowsFormsApplication2.Reference)
Before referencing SomethingElses.Local:
Name = 'AlphaTwo'
Parent = '' ()
Reference = 'Reference' ()
After referencing SomethingElses.Local:
Name = 'AlphaOne'
Parent = 'Alpha' (WindowsFormsApplication2.Parent)
Reference = '' (WindowsFormsApplication2.Reference)
After referencing SomethingElses.Local:
Name = 'AlphaTwo'
Parent = 'Alpha' (WindowsFormsApplication2.Parent)
Reference = 'Reference' ()
Before SaveChanges:
Name = 'AlphaOne'
Parent = 'Alpha' (WindowsFormsApplication2.Parent)
Reference = '' (WindowsFormsApplication2.Reference)
Before SaveChanges:
Name = 'AlphaTwo'
Parent = 'Alpha' (WindowsFormsApplication2.Parent)
Reference = 'Reference' ()
After SaveChanges:
Name = 'AlphaOne'
Parent = 'Alpha' (WindowsFormsApplication2.Parent)
Reference = 'Reference' (WindowsFormsApplication2.Reference)
After SaveChanges:
Name = 'AlphaTwo'
Parent = 'Alpha' (WindowsFormsApplication2.Parent)
Reference = 'Reference' (WindowsFormsApplication2.Reference)
Run Code Online (Sandbox Code Playgroud)
当实体添加到上下文时,是否有任何方法可以强制实体框架立即填充外键,而不是延迟它直到上下文发生其他情况?
选项1:
如果您只想修复实体之间的关系而不将它们保存到数据库,因此调用,DbContext.SaveChanges()则只需调用DbContext.ChangeTracker.DetectChanges().
选项2:
EF 可以自动修复实体之间的关系,无需进行校准DbContext.SaveChanges()或DbContext.ChangeTracker.DetectChanges(). 这些实体称为代理类。代理类是动态生成的派生类型,充当实体的代理。该代理会覆盖实体的一些虚拟属性,以插入挂钩,以便在访问该属性时自动执行操作。默认情况下为您启用代理创建DbContext,除非您通过调用禁用它DbContext.Configuration.ProxyEnabled = false;。您不需要添加该行代码,因为您需要启用代理创建。
无论如何,在利用此功能之前,您需要修改类上的一些内容:
ICollection<T>DbContext.DbSet<T>.Create()。按照此步骤,您的实体类必须如下所示:
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; }
}
Run Code Online (Sandbox Code Playgroud)
您的点击事件处理程序实现将如下所示:
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);
}
Run Code Online (Sandbox Code Playgroud)
此实现中有两个明显的变化:
Reference_Name = "Reference"不会帮助您的上下文延迟加载导航属性Refererence。这就是为什么延迟加载alphatwo.Reference_Name = "Reference";不会在数据库上找到任何内容,而alphatwo.Reference = reference;不是因为reference处于状态而这样做。Added| 归档时间: |
|
| 查看次数: |
3679 次 |
| 最近记录: |