Дополнение (1): Один из ответов сказал, что он должен работать. Поэтому я добавил полное исключение в конце этого сообщенияУдалить из коллекции в Entity Framework 6
Упрощенный: У меня есть последовательность объектов, каждая из которых содержит коллекцию других объектов. Примером этого является блог с коллекцией сообщений. MSDN использует это довольно часто в качестве примера
MSDN Code First to a new DataBase
Что я вижу в том, что если я создаю блог, я могу добавить некоторые сообщения, добавить блог в базу данных и вызвать SaveChanges. Структура сущности признает, что сообщения должны находиться в другой таблице с внешним ключом в таблице блогов.
Это именно то, как можно было бы создать базу данных, если бы Entity Framework не было вокруг.
Получение всех сообщений из блога и добавление сообщения может быть сделано без каких-либо знаний об отдельной почтовой таблице и внешнем ключе в таблице Blog.
Однако, когда я пытаюсь удалить сообщение из блога, я получаю ошибки в отношении внешних ключей.
Примечание: Следующая не об эффективности
public class Blog
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public virtual Blog Blog { get; set; }
}
public class BloggingContext : DbContext
{
public BloggingContext(string nameOrConnectionString)
: base(nameOrConnectionString){}
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
}
Использование будет выглядеть следующим образом:
class Program
{
static void Main(string[] args)
{
const string dbName = "MyTestDb";
Database.SetInitializer(new DropCreateDatabaseAlways <BloggingContext>());
using (var context = new BloggingContext(this.DbName))
{
// create a blog:
var blog = new Blog()
{
Name = "First Blog",
Posts = new List<Post>()
{
new Post() { Title = "My 1st Post", Content = "Hello World!" },
new Post() { Title = "My 2nd Post", Content = "All animals are equal but pigs are more equal"},
new Post() { Title = "My 3rd Post", Content = "Shall I compare thee to a summer's day" },
},
};
context.Blogs.Add(blog);
context.SaveChanges();
Хорошая вещь в том, что клиент не должен знать как фактически организована база данных. Клиент не должен знать, что Блог и Почта находятся в разных таблицах. Для клиента в блоге есть коллекция сообщений.
Аналогичным образом, если клиент запрашивает блог и получает доступ к сообщениям в блоге, Entity Framework знает, где получить сообщения. Клиент не должен знать, что сообщения сохраняются в другой таблице с внешним ключом.
blog = context.Blogs.First();
var lastPost = blog.Posts.Last();
Entity Framework даже при этом умный, что он не выбирает элементы, которые не нужны. Если бы я не хотел бы использовать коллекцию Post, то сообщения не будут извлечены из базы данных
Поэтому я ожидал, что следующий будет работать:
blog.Posts.Remove(lastPost);
context.AddOrUpdate(blog);
context.SaveChanges();
я ожидал, что структура субъекта знал бы, что последнее сообщение было удалено, и, таким образом, он должен будет удалить элемент из таблицы Posts. Но это не делает этого. Я получаю исключение: «Отношения не могут быть изменены, потому что одно или несколько свойств внешнего ключа не являются нулевыми. Bla bla», что означает, что сообщение должно быть удалено из таблицы Posts.
Вопрос: Правильно ли, что клиент не должен знать модель базы данных Entity Framework, за исключением случаев, когда данные должны быть удалены?
Дополнение: Конечно, я могу удалить элемент из DbSet, но мой вопрос: если Entity Framework достаточно умен, мне не нужно добавлять сообщение в DbSet, почему я должен его удалить?
Кто-то спросил текст исключения
System.InvalidOperationException был необработанное
- _HResult = -2146233079
_message = Сбой операции: Отношения не могут быть изменены из-за одно или несколько свойств внешнего ключа не имеют значения NULL. Когда происходит изменение отношения, соответствующее свойство внешнего ключа устанавливается равным нулевому значению. Если внешний ключ не поддерживает нулевые значения, необходимо определить новое отношение, для свойства внешнего ключа должно быть назначено другое ненулевое значение, или не связанный с ним объект должен быть удален.
HResult = -2146233079
- IsTransient = ложь
- Message = Сбой операции: Отношения не могут быть изменены, так как один или несколько внешних ключей свойств не является обнуляемым. Когда происходит изменение отношения, соответствующее свойство внешнего ключа устанавливается равным нулевому значению. Если внешний ключ не поддерживает нулевые значения, необходимо определить новое отношение, для свойства внешнего ключа должно быть назначено другое ненулевое значение, или не связанный с ним объект должен быть удален.
- Источник = EntityFramework
StackTrace: на System.Data.Entity.Core.Objects.ObjectContext.PrepareToSaveChanges (варианты SaveOptions) на System.Data.Entity.Core.Objects.ObjectContext.SaveChangesInternal (SaveOptions опции, Boolean executeInExistingTransaction) на System.Data.Entity.Core.Objects.ObjectContext.SaveChanges (варианты SaveOptions) на System.Data.Entity.Internal.InternalContext.SaveChanges() в System.Data.Entity.Internal.LazyInternalContext .SaveChanges() в System.Data.Entity.DbContext.SaveChanges() в Try InMemoryDbSet.TestDirectDbContext.Test2() в c: \ Users \ Harald \ Documents \ Visual Studio 2013 \ Projects \ EntityFramework \ TryInMemoryDbSet \ TryInMemoryDbSet \ TestDirectDbContext.cs: строка 75 в TryInMemoryDbSet.Program.Main (String [] args) в c : \ Users \ Harald \ Documents \ Visual Studio 2013 \ Projects \ EntityFramework \ TryInMemoryDbSet \ TryInMemoryDbSet \ Program.cs: линия 19 InnerException:
Вы пробовали 'blog.Posts.Remove (lastPost)', а затем вызываете 'context.SaveChanges()' вместо? – rexcfnghk
oops, ошибка ввода. Я исправлю это в своем вопросе –
Можете ли вы также опубликовать трассировку стека здесь? По моему опыту, он должен работать так, как ожидалось. Также вы попытались удалить вызов AddOrUpdate()? EF достаточно умен, чтобы определить объект как «EntityState.Modified», если ваша сущность отслеживается «DbContext» – rexcfnghk