关于c#:具有空导航属性的新Poco实体EF代码优先

New Poco Entity with null navigation property EF Code first

我先使用实体框架代码。以下是我的POCO课程:< BR>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class BusinessPartner
{
    [Key]
    public int BusinessPartnerID { get; set; }
    [Required]
    [StringLength(255)]
    public string Title { get; set; }
    [StringLength(255)]
    public string Address { get; set; }

    public virtual ICollection<BusinessPartnerLanguage> BusinessPartnerLanguage { get; set; }
}

public class Language
{
    [Key]
    public int LanguageID { get; set; }
    [Required]
    [StringLength(255)]
    public string Title { get; set; }
    [Required]
    public bool Active { get; set; }

    public virtual ICollection<BusinessPartnerLanguage> BusinessPartnerLanguage { get; set; }
}

public class BusinessPartnerLanguage
{
    [Key, Column(Order = 0)]
    public int BusinessPartnerID { get; set; }
    [Key, Column(Order = 1)]
    public int LanguageID { get; set; }
    [Required]
    public bool Default { get; set; }
    public virtual BusinessPartner BusinessPartner { get; set; }
    public virtual Language Language { get; set; }
}

当我在控制器中创建新实体时,如:< BR>

1
BusinessPartner bp = new BusinessPartner();

其导航属性bp.businesspartnerlanguage为空,< BR>所以如果我做一些类似的事情:

1
bp.BusinessPartnerLanguage.Add(someEntity);

我得到空异常。我通过将虚拟ICollection属性更改为:

1
2
3
4
5
6
   private ICollection<BusinessPartnerLanguage> _BusinessPartnerLanguage;
   public virtual ICollection<BusinessPartnerLanguage> BusinessPartnerLanguage
   {
       get { return this._BusinessPartnerLanguage ?? (this._BusinessPartnerLanguage = new HashSet<BusinessPartnerLanguage>()); }
       set { _BusinessPartnerLanguage = value; }
    }

但我想知道为什么这个方法不能正常工作,有没有更好的方法来解决这个问题。事先谢谢。


这是因为它只是一个POCO实体,如果从未设置该属性,它将为空。

从数据库上下文检索对象时,如果启用代理,则EF将创建代理实体。如果将该属性标记为虚拟,则对该虚拟属性的任何访问都将加载关系并初始化集合(如果该集合为空)。同样的情况下,也有急切的装载。

但如果数据库中不存在实体(新实体),则无法加载关系,它必须是现有实体。

如果您有现有的ID,则可以通过编程方式创建代理,而延迟加载将加载关系并初始化集合。但是您必须使用Create方法而不是新的运算符。

A proxy instance will not be created if you create an instance of an
entity using the new operator. - MSDN

1
2
3
4
5
6
7
var context = ...
int existingBPID = ...

var bp = context.Set<BusinessPartner>().Create(); // BusinessPartnerLanguage = null
bp.BusinessPartnerID = existingBPID;  // BusinessPartnerLanguage = null
context.Entry(bp).State = EntityState.Unchanged; // BusinessPartnerLanguage = null
var collection = bp.BusinessPartnerLanguage; // trigger lazy loading, BusinessPartnerLanguage != null

您还可以按照以下步骤简化属性。

1
2
3
4
5
6
private readonly ICollection<BusinessPartnerLanguage> _BusinessPartnerLanguage
    = new HashSet<BusinessPartnerLanguage>();
public virtual ICollection<BusinessPartnerLanguage> BusinessPartnerLanguage
{
    get { return _BusinessPartnerLanguage; }
}