【问题标题】:EF: how to delete many-to-many relationship without loading more than is neededEF:如何在不加载超出需要的情况下删除多对多关系
【发布时间】:2014-02-20 10:09:48
【问题描述】:

给定实体:TopicsSubscriptions 具有多对多关系以及相应的表:TopicsSubscriptionsTopicsSubscriptions,我只想从 TopicsSubscriptions 中删除一行EF,但不加载任何额外数据(可能只有 1 个主题和 1 个订阅除外)。

最后我希望 EF 生成与此类似的 SQL:

exec sp_executesql N'delete [dbo].[TopicSubscriptions]
where (([TopicId] = @0) and ([SubscriptionId] = @1))',N'@0 int,@1 int',@0=1,@1=2

我将LazyLoading 设置为false

我想我可以从这里得到答案:How to delete many-to-many relationship in Entity Framework without loading all of the data

var db = new TopicDBEntities(); var topic = db.Topics.FirstOrDefault(x => x.TopicId == 1);

// Get the subscription you want to delete var subscription =
db.Subscriptions.FirstOrDefault(x => x.SubscriptionId == 2);

// !!! This line does not work for me (Attach to ICollection<> ?!?) !!!
topic.Subscriptions.Attach(subscription); // Attach it (theObjectContext now 'thinks' it belongs to the topic)

topic.Subscriptions.Remove(subscription); // Remove it
db.SaveChanges(); // Flush changes

但后来我意识到 Attach 方法不属于 ICollection&lt;&gt;... 除非我遗漏了什么。

仅将一个订阅附加到一个主题的想法听起来不错,但我不明白如何实现它。

我使用的是DbContext 而不是ObjectContext 和Entity Framework 6,但我想应该没关系。

编辑:如果可能的话,最好找到一个没有存储过程或直接 sql 的解决方案,因为我必须在我的应用程序中支持许多数据库后端。

如果我不够清楚,我不需要删除实体,我只需要删除它们之间的关联。

【问题讨论】:

  • 如果您不想要下面的任何解决方案,那么您需要在表中添加一个 Payload 列,以便它在 EF 中映射并且可以引用为 dbContext.TopicSubscriptions。但是,这意味着您使用不必要的空间在表上使用了不必要的数据。除此之外,我不相信你有其他选择。
  • 我要注意上面的,它会影响你现有的代码。到什么程度,只有你自己知道。
  • 也许我的问题不够清楚,我只能从 db 加载一个特定主题和一个特定订阅,尽管我猜这些也可以附加到 DbSet。
  • 在您链接的问题中,dannie.f 的答案是一个可行的解决方案:stackoverflow.com/a/15294368/270591
  • 正是我刚刚尝试过的,并且工作起来就像一个魅力......谢谢

标签: c# entity-framework many-to-many dbcontext


【解决方案1】:

正如 Slauma 在他的 cmets 中所说,解决方案是 attach 实体,就像“dannie.f”在他的 answer 中所做的那样:

var db = new TopicDBEntities();

var topic = new Topic { TopicId = 1 };
var subscription = new Subscription { SubscriptionId = 2};
topic.Subscriptions.Add(subscription);

// Attach the topic and subscription as unchanged 
// so that they will not be added to the db   
// but start tracking changes to the entities
db.Topics.Attach(topic);

// Remove the subscription
// EF will know that the subscription should be removed from the topic
topic.subscriptions.Remove(subscription);

// commit the changes
db.SaveChanges();

【讨论】:

    【解决方案2】:

    假设您已对其进行了映射,因此您不能直接引用 TopicSubscriptions,并且只能引用 Topics 和 Subscriptions,以下适用。

    // Add a subscription to a topic
    var subscription = dbContect.Subscriptions.Find(2);
    var topic = dbContext.Topics.Find(1);
    
    // Recommend checking here, but omitted for example
    
    // Make the association
    topic.Subscriptions.Add(subscription);
    
    // Update
    dbContext.SaveChanges();
    

    从主题中删除订阅

    // Remove
    topic.Subscriptions.Remove(subscription);
    
    // Update
    dbContext.SaveChanges();
    

    如果您知道 Id 并想直接删除它,我建议在接受 @topicId 和 @subscriptionId 的数据库上使用简单的 StoredProcedure 并删除 TSQL 中的条目。

    @topicId INT,
    @subscriptionId INT
    
    DELETE FROM [dbo].[TopicSubscriptions] WHERE TopicId = @topicId AND SubscriptionId = @subscriptionId;
    

    然后您可以将 StoredProcedure 映射到 EF6 并从您的上下文中调用它。

    using (DbContext dbContext = new DbContext())
    {
    dbContext.DeleteTopicSubscriptionStoredProcedure(topicId, subscriptionId);
    }
    

    编辑 鉴于只有 SP 选项有效(对于缺少 Lazy-Loading 错误表示歉意),您也可以直接从 dbContext 执行 SQL。

    using (var dbContext = new DbContext())
    {
    string sql = @"DELETE FROM [dbo].[TopicSubscriptions] WHERE TopicId = @p0 AND SubscriptionId = @p1";
    context.Database.ExecuteSqlCommand(sql, topicId, subscriptionId);
    }
    

    【讨论】:

    • 好吧,删除关系的代码将不起作用,因为内部集合没有加载(LazyLoading 设置为 false)。存储过程确实可以工作,但 EF 也必须有办法。
    • @Cristi - 好的。我错过了那部分(是的,尽管它被突出显示)!编辑(在两分钟内)添加第三个选项,但我仍然觉得存储过程是更好的方法。
    【解决方案3】:

    我建议让实体框架通过像这样在流利的 api 中声明 cascade on delete 来处理删除;

    modelBuilder.Entity<Product>()
                .HasOptional(p => p.Category)
                .WithMany()
                .WillCascadeOnDelete(true);
    

    概述了完整的解决方案here

    【讨论】:

    • 我不需要删除实体,我只需要删除它们之间的关联
    • 那行不通,哈哈,你最终会得到很多冗余数据吗?!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-06
    • 1970-01-01
    • 2021-03-30
    • 1970-01-01
    • 1970-01-01
    • 2016-04-11
    • 2017-04-17
    相关资源
    最近更新 更多