Entity Framework 不是在添加时延迟加载 FK 集合
Entity Framework not Lazy Loading FK Collection on Add
我有以下用于 Entity Framework(版本 5)实施的数据库结构,该实施已工作多年,但由于某种循环引用问题而变得越来越慢。
[Table("Sensors", Schema = "Ems")]
public class Sensor
{
public Sensor()
{
SensorSamples = new List<SensorSample>() as ICollection<SensorSample>;
}
[Key]
public int Id { get; set; }
[Required, MaxLength(128)]
public string Name { get; set; }
[MaxLength(256)]
public string Description { get; set; }
[MaxLength(128)]
public string Location { get; set; }
[Required]
[MaxLength(15)]
public string IPAddress { get; set; }
[Required]
public int Port { get; set; }
[Required]
public bool Enabled { get; set; }
[Required, ForeignKey("Type")]
public int SensorTypeId { get; set; }
public virtual SensorType Type { get; set; }
[Required, ForeignKey("Network")]
public int SensorNetworkId { get; set; }
public virtual SensorNetwork Network { get; set; }
public virtual ICollection<SensorSample> SensorSamples { get; set; }
}
[Table("SensorSamples", Schema = "Ems")]
public class SensorSample
{
public SensorSample()
{
SampleData = new List<SampleData>() as ICollection<SampleData>;
}
[Key]
public int Id { get; set; }
[Required, ForeignKey("Sensor")]
public int SensorId { get; set; }
public virtual Sensor Sensor { get; set; }
[Required]
public DateTime SampleTime { get; set; }
[Required]
public virtual ICollection<SampleData> SampleData { get; set; }
}
[Table("SampleData", Schema = "Ems")]
public class SampleData
{
public SampleData()
{
}
[Key]
public int Id { get; set; }
[Required, ForeignKey("DataType")]
public int SampleDataTypeId { get; set; }
public virtual SampleDataType DataType { get; set; }
[Required, ForeignKey("Unit")]
public int SampleUnitId { get; set; }
public virtual SampleUnit Unit { get; set; }
[Required, ForeignKey("Sample")]
public int SensorSampleId { get; set; }
public virtual SensorSample Sample { get; set; }
[MaxLength(128)]
public string Value { get; set; }
}
当我使用以下代码添加新的 SensorSample
时,添加第一个代码需要很长时间,因为它实例化了 SensorSample
并将其添加到 Samples
集合在 Sensor
个实例上。
Sensor sensor = GetSensor(1);
SensorSample sample = new SensorSample();
sample.SampleTime = d.Timestamp;
sample.SensorId = sensor.Id;
sensor.SensorSamples.Add(sample);
如何在 Sensor
上向 SensorSamples
添加示例而不实例化现有 SensorSamples
的整个集合?我目前将 AutoDetectChangesEnabled
设置为 false,并将 DetectChanges
延迟到 SaveChanges
之前。这没有区别。我没有关闭 LazyLoading
但在这种情况下它似乎并没有像我预期的那样启动。我认为 LazyLoading 满足所有要求,例如具有 public 无参数构造函数。我错过了什么吗?任何想法为什么会这样?谢谢。
我很清楚为什么会发生这种情况:当 EF 从数据库加载某些内容时,它不会 return 您的类型,而是 return 一个 class源自你的。如果此 class 具有 EF 可以从中推断出关系的虚拟属性,则此 class 会实现虚拟属性,以便在访问时从存储中加载关联的对象。随着越来越多的外键与实例相关联,这样的操作可能会变得很长。
为了避免这种情况,只需创建一个传感器示例实例,在您的业务模型和存储模型之间进行映射,并设置将示例与传感器相关联的外键。完成后,将示例添加到 DbContext 中的正确 DbSet 并保存更改。
大致如下:
var sample = new SensorSample();
.. Map properties and values from business to storage model
//Map the sensor foreign key for this sample
sample.SensorId = sensor.Id;
context.SensorSamples.Add(sample);
context.SaveChanges();
旁注:
不要在 EF 中使用惰性虚拟集合功能,除非您知道结果集是有界的。
我有以下用于 Entity Framework(版本 5)实施的数据库结构,该实施已工作多年,但由于某种循环引用问题而变得越来越慢。
[Table("Sensors", Schema = "Ems")]
public class Sensor
{
public Sensor()
{
SensorSamples = new List<SensorSample>() as ICollection<SensorSample>;
}
[Key]
public int Id { get; set; }
[Required, MaxLength(128)]
public string Name { get; set; }
[MaxLength(256)]
public string Description { get; set; }
[MaxLength(128)]
public string Location { get; set; }
[Required]
[MaxLength(15)]
public string IPAddress { get; set; }
[Required]
public int Port { get; set; }
[Required]
public bool Enabled { get; set; }
[Required, ForeignKey("Type")]
public int SensorTypeId { get; set; }
public virtual SensorType Type { get; set; }
[Required, ForeignKey("Network")]
public int SensorNetworkId { get; set; }
public virtual SensorNetwork Network { get; set; }
public virtual ICollection<SensorSample> SensorSamples { get; set; }
}
[Table("SensorSamples", Schema = "Ems")]
public class SensorSample
{
public SensorSample()
{
SampleData = new List<SampleData>() as ICollection<SampleData>;
}
[Key]
public int Id { get; set; }
[Required, ForeignKey("Sensor")]
public int SensorId { get; set; }
public virtual Sensor Sensor { get; set; }
[Required]
public DateTime SampleTime { get; set; }
[Required]
public virtual ICollection<SampleData> SampleData { get; set; }
}
[Table("SampleData", Schema = "Ems")]
public class SampleData
{
public SampleData()
{
}
[Key]
public int Id { get; set; }
[Required, ForeignKey("DataType")]
public int SampleDataTypeId { get; set; }
public virtual SampleDataType DataType { get; set; }
[Required, ForeignKey("Unit")]
public int SampleUnitId { get; set; }
public virtual SampleUnit Unit { get; set; }
[Required, ForeignKey("Sample")]
public int SensorSampleId { get; set; }
public virtual SensorSample Sample { get; set; }
[MaxLength(128)]
public string Value { get; set; }
}
当我使用以下代码添加新的 SensorSample
时,添加第一个代码需要很长时间,因为它实例化了 SensorSample
并将其添加到 Samples
集合在 Sensor
个实例上。
Sensor sensor = GetSensor(1);
SensorSample sample = new SensorSample();
sample.SampleTime = d.Timestamp;
sample.SensorId = sensor.Id;
sensor.SensorSamples.Add(sample);
如何在 Sensor
上向 SensorSamples
添加示例而不实例化现有 SensorSamples
的整个集合?我目前将 AutoDetectChangesEnabled
设置为 false,并将 DetectChanges
延迟到 SaveChanges
之前。这没有区别。我没有关闭 LazyLoading
但在这种情况下它似乎并没有像我预期的那样启动。我认为 LazyLoading 满足所有要求,例如具有 public 无参数构造函数。我错过了什么吗?任何想法为什么会这样?谢谢。
我很清楚为什么会发生这种情况:当 EF 从数据库加载某些内容时,它不会 return 您的类型,而是 return 一个 class源自你的。如果此 class 具有 EF 可以从中推断出关系的虚拟属性,则此 class 会实现虚拟属性,以便在访问时从存储中加载关联的对象。随着越来越多的外键与实例相关联,这样的操作可能会变得很长。
为了避免这种情况,只需创建一个传感器示例实例,在您的业务模型和存储模型之间进行映射,并设置将示例与传感器相关联的外键。完成后,将示例添加到 DbContext 中的正确 DbSet 并保存更改。
大致如下:
var sample = new SensorSample();
.. Map properties and values from business to storage model
//Map the sensor foreign key for this sample
sample.SensorId = sensor.Id;
context.SensorSamples.Add(sample);
context.SaveChanges();
旁注:
不要在 EF 中使用惰性虚拟集合功能,除非您知道结果集是有界的。