在运行时创建新实体时,如何处理EF中的NullReferences?

时间:2015-01-24 07:43:42

标签: c# entity-framework

我有以下示例架构:

public class CounterReading
{
    public int CounterReadingId { get; set; }
    public virtual Counter Counter { get; set; }
    public DateTime Date { get; set; }
    public decimal Reading { get; set; }

    public CounterReading()
    {
        Date = DateTime.Now;
    }
}

public class Counter
{
    [Key, ForeignKey("Meter")]
    public int CounterId { get; set; }

    public virtual Meter Meter { get; set; }
    public virtual ObservableCollection<CounterReading> Readings { get; set; }

    [NotMapped]
    public CounterReading CurrentReading
    {
        get
        {
            if(Readings.Count > 0)
            {
                return Readings.MaxBy(m => m.Reading);
            }
            return null;
        }
    }
}

public abstract class Meter
{
    public int MeterId { get; set; }
    public string EANNumber { get; set; }
    public string MeterNumber { get; set; }
    public virtual Premise Premise { get; set; }
}

public class WaterMeter : Meter
{
    public virtual Counter Counter { get; set; }

    public WaterMeter()
    {
        Counter = new Counter();
        Counter.Readings = new ObservableCollection<CounterReading>();
    }
}

当我从数据库加载WaterMeter时,我的CounterReadings没有任何Counter,这是行不通的。这是因为我在构造函数中设置了NullReferencesExceptions,以便在运行时创建新的WaterMeter时避免WaterMeter

如果我删除了{{1}}构造函数,EF会很好地加载我的读数。但这意味着我在使用我的应用程序时会有大量的NullReferences,而不是每次都重新加载我的数据。

解决这个问题的最佳方法是什么?

编辑: NRE: enter image description here

3 个答案:

答案 0 :(得分:1)

首先,您的问题中的代码和您正在执行的实际代码(根据您添加的图像)存在脱节,这就是我无法查看问题的原因。

但是,从您发布的图片中可以清楚地看出问题在于您Readingsprivate字段 - EF CodeFirst要求将导航属性标记为{{ 1}}以便初始化它们。

答案 1 :(得分:0)

要避免带有集合的空引用异常,您应该引入本地只读集合字段并将其初始化为空集合。

    public class Counter
{
    private readonly ObservableCollection<CounterReading> readings = new ObservableCollection<CounterReading>();

    public virtual ObservableCollection<CounterReading> Readings
    {
        get { return readings; }
        set { readings = value; }
    }

    [Key, ForeignKey("Meter")]
    public int CounterId { get; set; }

    public virtual Meter Meter { get; set; }

    [NotMapped]
    public CounterReading CurrentReading
    {
        get
        {
           return Readings.MaxBy(m => m.Reading);
        }
    }
}

答案 2 :(得分:0)

我对Evgeny的答案有一个补充。您可以有条件地创建集合的新实例,而不是始终创建集合的新实例,因此它只在实际调用此属性时创建新实例:

private readonly ObservableCollection<CounterReading> readings;
public virtual ObservableCollection<CounterReading> Readings
{
    get 
    { 
       if(_readings == null) 
       {
         _readings = new ObservableCollection<CounterReading>();
       }
       return readings; 
    }
    set { readings = value; }
}

如果您不需要为getter和setter添加逻辑,为什么不考虑使用它:

public virtual ObservableCollection<CounterReading> Readings {get;set;}