我有一个名为 Driver 的模型,其中包含一个“DriverQualifications”列表,更新时我想添加/删除/更新当前 DriverQualifications 的值。
我当前尝试通过首先清除列表并读取所有元素来更新:
public void UpdateOne(Driver val)
{
using (var db = new COMP1690Entities())
{
Driver d = db.Drivers.Where((dr) => dr.Id == val.Id).Include("DriverQualifications.Qualification").FirstOrDefault();
d.DriverQualifications.Clear();
foreach (DriverQualification q in val.DriverQualifications)
{
q.Fk_Qualifications_Id = q.Qualification.Id;
q.Qualification = null;
d.DriverQualifications.Add(q);
}
d.Phone_Number = val.Phone_Number;
db.SaveChanges();
}
}
这会导致“违反多重性约束”。关系“COMP1690Model.DriverQualifications_ibfk_1”的角色“Drivers”具有多重性1或0..1。
我如何向数据库添加值:
public void CreateOne(Driver val)
{
using (var db = new COMP1690Entities())
{
foreach(DriverQualification q in val.DriverQualifications)
{
q.Fk_Qualifications_Id = q.Qualification.Id;
q.Qualification = null;
}
db.Drivers.Add(val);
db.SaveChanges();
}
}
驱动型号:
public partial class Driver
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Driver()
{
this.DriverQualifications = new HashSet<DriverQualification>();
this.DriverTrainings = new HashSet<DriverTraining>();
}
public int Id { get; set; }
public string Phone_Number { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<DriverQualification> DriverQualifications { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<DriverTraining> DriverTrainings { get; set; }
}
驾驶员资格模型:
public partial class DriverQualification
{
public int Id { get; set; }
public Nullable<System.DateTime> Expiry_Date { get; set; }
public int Fk_Driver_Id { get; set; }
public int Fk_Qualifications_Id { get; set; }
public virtual Driver Driver { get; set; }
public virtual Qualification Qualification { get; set; }
}
在处理 EF 和引用(DriverQualification -> Qualification)时,请使用引用,而不是 FK。事实上,我通常建议不要向实体添加 FK,而是使用影子属性 (EF Core) 或.Map()
在实体配置中避免它们可访问。您面临的问题是 EF 仍在跟踪引用特定 Qualification 的 DriverQualification 实体,因此将 Qualification 设置为 null 并更新 FK 并不起作用。
因此,您要传回一个驱动程序,想要重新加载该驱动程序实体,并根据传入的驱动程序更新其资格。
假设传入的驱动程序来自客户端(Web 应用程序等)并已被修改,我们不能“信任”它,或者它是参考数据,因此最好将其重新加载而不是重新附加到上下文。
编辑:我建议使用 ViewModel 而不是传递实体,即使您不打算信任它。传递实体的主要风险是在更新时很容易重新附加/使用它或引用的实体。我不得不再次检查这个答案,因为我认为在获得更新的资格时我违反了这条规则!:) 例如,将实体图传递给客户端浏览器也会比您应该公开更多有关您的域的信息。即使不显示各种列/fks/reference 数据,客户端也可以使用调试工具查看这些数据。网络上的数据也多于可能需要的数据。Automapper 可以使转置实体以快速查看模型,并且也可以使用IQueryable
。( ProjectTo
). /编辑
为了清楚起见,我重命名了一些变量..(即 val => updatedDriver)
using (var context = new COMP1690Entities())
{
var updatedQualificationIds = updatedDriver.DriverQualifications.Select(dq => dq.Qualification.Id).ToList();
// Get the updated qualification entities from the DB.
var updatedQualifications = context.Qualifications.Where(q => updatedQualificationIds.Contains(q.Id)).ToList();
var driver = context.Drivers.Where(d => d.Id == updatedDriver.Id)
.Include(d => d.DriverQualifications)
.Include("DriverQualifications.Qualification").Single();
var driverQualificationsToRemove = driver.DriverQualifications
.Where(dq => !updatedQualificationIds.Contains(udq.Qualification.Id));
foreach(var driverQualification in driverQualificationsToRemove)
driver.DriverQualifications.Remove(driverQualification);
var driverQualificationsToAdd = updatedDriverQualifications
.Except(driver.DriverQualifications.Select(dq => dq.Qualification),
new LamdaComparer((q1,q2) => q1.Id == q2.Id))
.Select(q => new DriverQualification { Qualification = q })
.ToList();
driver.DriverQualifications.AddRange(driverQualificationsToAdd);
driver.PhoneNumber = updatedDriver.PhoneNumber;
context.SaveChanges();
}
这假设我们要删除不再与驱动程序关联的资格关联,并添加任何尚未关联的新资格。(保留任何不变的资格。)
您可以在此处找到的 LamdaComparer
基本上,为了避免引用/关键问题,坚持更新引用并完全忽略 FK。对于我需要进行大量“原始”更新的实体/上下文,我将仅声明 FK 并放弃添加性能参考。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句