鉴于具有多对多关系的实体:Topics
和Subscriptions
以及相应的表:Topics
,Subscriptions
,TopicsSubscriptions
,我想要使用EF仅从TopicsSubscriptions
删除一行,但不加载任何额外数据(可能只有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<>
的方法...除非我遗漏了什么。
只为一个主题附加一个订阅的想法听起来不错,但我无法理解如何实现它。
我使用的是DbContext
而不是ObjectContext
和实体框架6,但我想这应该不重要。
编辑:如果可能的话,找到没有存储过程或直接sql的解决方案会很好,因为我必须在我的应用程序中支持许多数据库后端。
如果我不够清楚,我不需要删除实体,我只需要删除它们之间的关联。
答案 0 :(得分:1)
正如Slauma在评论中所说,解决方案是附加实体,就像“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();
答案 1 :(得分:0)
假设您已映射它以便您无法直接引用TopicSubscriptions,并且只能引用主题和订阅,则以下情况适用。
// 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并且想直接删除它,我建议在数据库上使用简单的StoredProcedure接受@topicId和@subscriptionId并删除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);
}
EDIT 只有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);
}
答案 2 :(得分:0)
我建议让实体框架通过像这样在流畅的api中声明cascade on delete
来处理删除;
modelBuilder.Entity<Product>()
.HasOptional(p => p.Category)
.WithMany()
.WillCascadeOnDelete(true);
概述了完整的解决方案here。