【发布时间】:2018-05-31 10:42:33
【问题描述】:
我在应用程序中遇到了一个奇怪的问题。我有以下代码更新父实体并添加新的子实体。
Item item = db.Items.Find(Id);
if (newSubItems.Count() > 0)
{
newSubItems.ForEach(x =>
{
var subItem = new SubItem();
subItem.Name = x.Name;
item.SubItems.Add(subItem);
});
}
item.ModifiedAt = DateTime.Now;
item.ModifiedBy = UserId;
db.Entry(item).State = EntityState.Modified;
using (var s = db.Database.BeginTransaction(isolationLevel: IsolationLevel.RepeatableRead))
{
await db.SaveChangesAsync();
s.Commit();
logger.info("Updated successfully.");
}
此代码在我的本地环境中运行良好。如果我提供新的子项,这些子项将成功添加到相应的表中。
型号如下。
public partial class Item
{
public Item()
{
this.SubItems = new HashSet<SubItem>();
}
public int Id { get; set; }
public DateTime ModifiedAt { get; set; }
public int ModifiedBy { get; set; }
public virtual ICollection<SubItem> SubItems { get; set; }
}
public partial class SubItem
{
public int Id { get; set; }
public string Name { get; set; }
public int ItemId { get; set; }
public Item Item { get; set; }
}
但是,这在我的生产环境中无法正常工作。父实体已更新,但如果没有现有的子实体,则不会添加新的子实体。我检查了日志,我可以看到记录了“更新成功”。如果父实体至少有 1 个子实体,则成功添加新的子实体。
所以现在作为生产环境中的一种解决方法,我在使用以下代码进行第一次保存操作后再次重新添加子项。
int subItemsCount = db.SubItems.Where(a => a.ItemId == item.Id).Count();
if (subItemsCount == 0 && newSubItems.Count() > 0)
{
logger.info(string.Format("Sub-items are not added for Id - {0}. Adding those again.", item.Id));
newSubItems.ForEach(x =>
{
var subItem = new SubItem();
subItem.Name = x.Name;
subItem.ItemId = item.Id;
db.SubItems.Add(subItem);
});
await db.SaveChangesAsync();
logger.info(string.Format("Sub-items re-added successfully for Id - {0}.", item.Id));
}
现在查看生产环境的日志,我可以看到“没有为 Id 添加子项”的消息被记录了很多次,并且在第二次保存操作中成功添加了子项。
想知道是否有人仅在特定环境中知道这种奇怪行为的原因。
【问题讨论】:
-
在获取项目详细信息时尝试包含子项目(使用 .Include)
Item item = db.Items.Find(Id);使用Item item = db.Items.Include(i => i.SubItems).Where(i => i.Id == Id); -
另外,您可能不需要
db.Entry(item).State = EntityState.Modified;,因为您未处于分离模式(除非您已明确禁用更改跟踪) -
@Developer 感谢您的建议。我相信,默认情况下,应该加载所有子实体并且需要
.Include,前提是我手动禁用了LazyLoadingEnabled属性。我将尝试按照您的建议删除将状态更新为modified的第二条语句,但我仍然不确定该语句是否会导致这样的问题。 -
能否请您检查生产数据库中的外键关系是否设置正确?同样在您的
SubItem实体中,缺少Item的导航属性以使 EF 了解 Item 外键 - 不确定您是否使用流畅的语法设置它 -
@Developer FK 关系在生产中是正确的。我什至尝试在我的开发环境中使用生产数据库副本,它工作正常。在此处添加示例模型时,我错过了导航属性。现在更正它。
标签: c# sql-server entity-framework linq