我已经声明了这样的实体(实际的类显然也有ID属性,映射完成等等,但不是问题,所以我在这里跳过它):
Sub Debugging()
Workbooks("Problem.xls").Worksheets(1).Activate
Cash_Rows = 5
Share_Rows = 6
If Cash_Rows <= Share_Rows Then
Range("A1:A" & Cash_Rows).Select
With Selection.Interior
.ThemeColor = xlThemeColorAccent6
.TintAndShade = 0.399975585192419
Count_Cash = Application.WorksheetFunction.CountIf(Range("A:A"), "L*")
For Each cell In Range("A1:A" & Cash_Rows)
If CStr(cell.Value) Like "L*" Then
Range("A" & cell.Row & ":" & "D" & cell.Row).Interior.Color = 65535
Dim Index As Integer
Index = Application.WorksheetFunction.Match(CStr(cell.Value), Range("F2:" & "F" & Share_Rows), 0)
Range("F" & Index & ":" & "I" & Index).Interior.Color = 65535
End If
Next
If Count_Cash = 0 Then
MsgBox "You do not have any matching ID+Amount between Cash and Shares booking. It's OK!"
Else
MsgBox "You have " & Count_Cash & " matching transactions. Check them!"
End If
Else
MsgBox "Do not worry. Be happy!"
End If
End Sub
这很完美:
public class Parent
{
public virtual ICollection<Child> Children {get; set;}
}
现在我更改要保护的Children集合的可见性:
public class Consumer
{
void DoBusiness()
{
using (var ctx = new MyDbContext())
{
var entity = ctx.Parents.Find(keyOfParent);
// This is as expected: entity.Children refers to a collection which
// Entity Framework has assigned, a collection which supports lazy loading.
}
}
}
这会带来意想不到的结果:
public class Parent
{
protected virtual ICollection<Child> Children {get; set;}
}
此外,如果我处于保护儿童的情况下,请尝试通过以下方式明确加载儿童:
public class Consumer
{
void DoBusiness()
{
using (var ctx = new MyDbContext())
{
var entity = ctx.Parents.Find(keyOfParent);
// This is NOT as expected: entity.Children is null. I would expect, that it
// had been referring to a collection which Entity Framework would have been
// assigning, a collection which should support lazy loading.
}
}
}
然后我得到了这个例外:
'Parent'类型的属性“Children”不是导航属性.Reference和Collection方法只能用于导航属性。使用Property或ComplexProperty方法。
因此:为了使用Entity Framework获得受保护的导航属性,我应该做些什么?
答案 0 :(得分:1)
以下是我如何使其发挥作用。
public class Parent
{
public int Id { get; set; }
public string Name { get; set; }
internal ICollection<Child> children;
protected virtual ICollection<Child> Children { get { return children; } set { children = value; } }
internal ICollection<Child> GetChildren() => Children;
internal static Expression<Func<Parent, ICollection<Child>>> ChildrenSelector => p => p.Children;
}
public class Child
{
public int Id { get; set; }
public string Name { get; set; }
internal Parent parent;
protected virtual Parent Parent { get { return parent; } set { parent = value; } }
internal Parent GetParent() => Parent;
internal static Expression<Func<Child, Parent>> ParentSelector => c => c.Parent;
}
public class MyDbContext : DbContext
{
public DbSet<Parent> Parents { get; set; }
public DbSet<Child> Children { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Parent>()
.HasMany(Parent.ChildrenSelector)
.WithRequired(Child.ParentSelector)
.Map(a => a.MapKey("ParentId"));
base.OnModelCreating(modelBuilder);
}
}
使用的显式字段不是必需的 - 我将它们放在那里以便能够观察其中的内容,您可以继续使用自动属性。
关键部分是提供属性访问器表达式并将其与Fluent API配置一起使用。如果没有显式配置,您将获得您描述的行为。有了它,一切正常。
例如,延迟加载:
var parent = ctx.Parents.Find(keyOfParent);
var children = parent.GetChildren();
或显式加载:
var parent = ctx.Parents.Find(keyOfParent);
db.Entry(parent).Collection("Children").Load();
var children = parent.children;
更新:非常奇怪,如果我们更换配置代码
modelBuilder.Entity<Parent>()
.HasMany(Parent.ChildrenSelector)
.WithRequired(Child.ParentSelector)
.Map(a => a.MapKey("ParentId"));
完全等同于定义
modelBuilder.Entity<Child>()
.HasRequired(Child.ParentSelector)
.WithMany(Parent.ChildrenSelector)
.Map(a => a.MapKey("ParentId"));
数据库表和FK是相同的,但加载不起作用!因此,工作解决方案无意中撞到了后门,或者EF中存在错误。在这两种情况下,该功能对我来说似乎都有问题,我只会使用public
访问器以避免意外。