实体框架核心:删除关系但不删除实体

时间:2017-12-03 07:07:17

标签: c# asp.net-core entity-framework-core

如果您拥有2个实体但没有“关系”实体,您将如何删除关系?

假设以下实体......

模型类:

public class DisplayGroup
{
        [Key]
        public int GroupId { get; set; }
        public string Description { get; set; }
        public string Name { get; set; }
        public ICollection<LookUpGroupItem> LookUpGroupItems { get; set; }
}

public class DisplayItem
{
        [Key]
        public int ItemId { get; set; }
        public string Description { get; set; }
        public string FileType { get; set; }
        public string FileName { get; set; }
        public ICollection<LookUpGroupItem> LookUpGroupItems { get; set; }
}

public class LookUpGroupItem
{
        public int ItemId { get; set; }
        public DisplayItem DisplayItem { get; set; }
        public int GroupId { get; set; }
        public DisplayGroup DisplayGroup { get; set; }
}

以下是删除关系的代码。 注意:我不想删除实体,他们只是不再共享关系。

public void RemoveLink(DisplayGroup g, DisplayItem d)
{
    _dataContext.Remove(g.LookUpGroupItems.Single(x => x.ItemId == d.ItemId));
}

上述方法会导致错误:

  

发生了System.ArgumentNullException   消息=值不能为空。

看起来就是这种情况,因为LookUpGroupItems为空,但是这些是从数据库中调用的。我同意我不想在从数据库中获取Get时加载所有实体关系对象,但是,最有效的方法是什么?

附加说明:此问题与参数null异常无关。它明确说明了如何删除Entity Framework Core中的关系。

1 个答案:

答案 0 :(得分:2)

以下 效率最高,但是可靠方式最多

public void RemoveLink(DisplayGroup g, DisplayItem d)
{
    var link = _dataContext.Find<LookUpGroupItem>(g.GroupId, d.ItemId); // or (d.ItemId, g.GroupId) depending of how the composite PK is defined
    if (link != null)
        _dataContext.Remove(link);
}

简单明了。 Find方法用于在本地缓存中定位实体或从数据库加载实体。如果找到,则使用Remove方法将其标记为删除(将在您调用SaveChanges时应用)。

当实体未包含在本地缓存中时,由于数据库往返而不是最有效的。

效率最高的是使用&#34; stub&#34;实体(仅填充FK属性):

var link = new LookUpGroupItem { GroupId = g.GroupId, ItemId = d.ItemId };
_dataContext.Remove(link);

这只会在调用DELETE时发出ApplyChanges SQL命令。但它有以下缺点:

(1)如果_dataContext已经包含(正在跟踪)具有相同PK的LookUpGroupItem实体,则Remove调用会抛出InvalidOperationException类似的内容&#34;实体类型的实例&#39; LookUpGroupItem&#39;无法跟踪,因为另一个具有键值&#39; GroupId:1,ItemId:1&#39;已被跟踪。附加现有实体时,请确保仅附加一个具有给定键值的实体实例。&#34;

(2)如果数据库表不包含具有指定复合PK的记录,SaveChanges将抛出DbUpdateConcurrencyException&#34;数据库操作预计会影响1行(s )但实际上影响了0行。自加载实体以来,数据可能已被修改或删除。有关理解和处理乐观并发异常的信息,请参阅http://go.microsoft.com/fwlink/?LinkId=527962&#34; (这种行为实际上被包括我在内的很多人认为是一个错误,但事实就是如此)。

简而言之,只有在为该操作使用短期新创建DbContext时才能使用优化方法,并且您绝对确定数据库中存在具有此类PK的记录。在所有其他情况下(通常),您应该使用第一种方法。