#c# #asp.net-core #entity-framework-core
#c# #asp.net-ядро #.net-ядро #entity-framework-core
Вопрос:
Я новичок в EF Core, и, используя это руководство, я получил неожиданный результат, а именно: данные выглядят нормально в модели, когда они только что заполнены, но в новом экземпляре контекста свойство навигации в основном объекте не заполнено, а свойство навигации в зависимомсущность заполняется особым образом.
Вот модель (код из руководства немного изменен):
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
namespace EFGetStarted
{
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
options.UseSqlite("Data Source=blogging.db");
}
}
public class Blog
{
public int BlogId { get; set; }
public string Name { get; set; }
public List<Post> Posts { get; } = new List<Post>();
public override string ToString()
{
return
"{"
"BlogId: " BlogId ", "
"Name: " Name ", "
"Posts.Count: " Posts.Count
"}";
}
}
public class Post
{
public int PostId { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
public override string ToString()
{
return
"{"
"PostId: " PostId ", "
"Content: " Content ", "
"BlogId: " BlogId
"}";
}
}
}
И вот программа:
using static System.Console;
namespace EFGetStarted
{
class Program
{
static void Main()
{
CreateContents(new BloggingContext());
Print(new BloggingContext());
}
static void CreateContents(BloggingContext db)
{
AddBlog(db);
Print(db);
}
private static void AddBlog(BloggingContext db)
{
var blog = new Blog { Name = "Blog 1" };
db.Add(blog);
blog.Posts.Add(new Post { Content = "Post 1" });
blog.Posts.Add(new Post { Content = "Post 2" });
blog.Posts.Add(new Post { Content = "Post 3" });
db.SaveChanges();
}
private static void Print(BloggingContext db)
{
PrintBlogs(db);
PrintPosts(db);
}
private static void PrintBlogs(BloggingContext db)
{
WriteLine("---- Blogs: ----");
foreach (var blog in db.Blogs) Print(blog);
WriteLine("");
}
private static void PrintPosts(BloggingContext db)
{
WriteLine("---- Posts: ----");
foreach (var post in db.Posts) Print(post);
WriteLine("");
}
private static void Print(Blog blog)
{
WriteLine(blog);
foreach (var post in blog.Posts) WriteLine(post);
WriteLine();
}
private static void Print(Post post)
{
WriteLine(post);
WriteLine(post.Blog);
foreach (var blogPost in post.Blog.Posts) WriteLine(blogPost);
WriteLine();
}
}
}
Программа выдает следующий вывод:
---- Blogs: ----
{BlogId: 1, Name: 'Blog 1', Posts.Count: 3}
{PostId: 1, Content: 'Post 1', BlogId: 1}
{PostId: 2, Content: 'Post 2', BlogId: 1}
{PostId: 3, Content: 'Post 3', BlogId: 1}
---- Posts: ----
{PostId: 1, Content: 'Post 1', BlogId: 1}
{BlogId: 1, Name: 'Blog 1', Posts.Count: 3}
{PostId: 1, Content: 'Post 1', BlogId: 1}
{PostId: 2, Content: 'Post 2', BlogId: 1}
{PostId: 3, Content: 'Post 3', BlogId: 1}
{PostId: 2, Content: 'Post 2', BlogId: 1}
{BlogId: 1, Name: 'Blog 1', Posts.Count: 3}
{PostId: 1, Content: 'Post 1', BlogId: 1}
{PostId: 2, Content: 'Post 2', BlogId: 1}
{PostId: 3, Content: 'Post 3', BlogId: 1}
{PostId: 3, Content: 'Post 3', BlogId: 1}
{BlogId: 1, Name: 'Blog 1', Posts.Count: 3}
{PostId: 1, Content: 'Post 1', BlogId: 1}
{PostId: 2, Content: 'Post 2', BlogId: 1}
{PostId: 3, Content: 'Post 3', BlogId: 1}
---- Blogs: ----
{BlogId: 1, Name: 'Blog 1', Posts.Count: 0}
---- Posts: ----
{PostId: 1, Content: 'Post 1', BlogId: 1}
{BlogId: 1, Name: 'Blog 1', Posts.Count: 1}
{PostId: 1, Content: 'Post 1', BlogId: 1}
{PostId: 2, Content: 'Post 2', BlogId: 1}
{BlogId: 1, Name: 'Blog 1', Posts.Count: 2}
{PostId: 1, Content: 'Post 1', BlogId: 1}
{PostId: 2, Content: 'Post 2', BlogId: 1}
{PostId: 3, Content: 'Post 3', BlogId: 1}
{BlogId: 1, Name: 'Blog 1', Posts.Count: 3}
{PostId: 1, Content: 'Post 1', BlogId: 1}
{PostId: 2, Content: 'Post 2', BlogId: 1}
{PostId: 3, Content: 'Post 3', BlogId: 1}
Как вы можете видеть, при создании модели в блоге есть три сообщения, и каждое сообщение ссылается на блог с теми же тремя сообщениями.
При печати с использованием нового экземпляра контекста в блоге нет сообщений, и, похоже, сообщения ссылаются на разные экземпляры блога, у каждого из которых разное количество связанных сообщений.
Как сделать так, чтобы модель в новом экземпляре контекста выглядела так, как та, в которой она была заполнена?
Комментарии:
1. Что вы имеете в
When printed in a new connection
виду?2. Возможно, это было неверно, но под «новым подключением» я подразумевал «новый экземпляр контекста». Я предположил, что при создании экземпляра контекста создается новое соединение с базой данных.
Ответ №1:
В коде есть ошибка. В коде нет инструкции include, поэтому вы не можете видеть сообщения. Попробуйте это:
private static void PrintBlogs(BloggingContext db)
{
var blogs = db.Blogs.Include(i => i.Posts).ToArray();
WriteLine("---- Blogs: ----");
foreach (var blog in blogs) Print(blog);
WriteLine("");
}
private static void PrintPosts(BloggingContext db)
{
var posts = db.Posts.Include(i => i.Blog).ToArray();
WriteLine("---- Posts: ----");
foreach (var post in posts) Print(post);
WriteLine("");
}
Теперь результат:
---- Blogs: ----
{BlogId: 1, Name: Blog 1, Posts.Count: 3}
{PostId: 1, Content: Post 1, BlogId: 1}
{PostId: 2, Content: Post 2, BlogId: 1}
{PostId: 3, Content: Post 3, BlogId: 1}
---- Posts: ----
{PostId: 1, Content: Post 1, BlogId: 1}
{BlogId: 1, Name: Blog 1, Posts.Count: 3}
{PostId: 1, Content: Post 1, BlogId: 1}
{PostId: 2, Content: Post 2, BlogId: 1}
{PostId: 3, Content: Post 3, BlogId: 1}
{PostId: 2, Content: Post 2, BlogId: 1}
{BlogId: 1, Name: Blog 1, Posts.Count: 3}
{PostId: 1, Content: Post 1, BlogId: 1}
{PostId: 2, Content: Post 2, BlogId: 1}
{PostId: 3, Content: Post 3, BlogId: 1}
{PostId: 3, Content: Post 3, BlogId: 1}
{BlogId: 1, Name: Blog 1, Posts.Count: 3}
{PostId: 1, Content: Post 1, BlogId: 1}
{PostId: 2, Content: Post 2, BlogId: 1}
{PostId: 3, Content: Post 3, BlogId: 1}
Комментарии:
1. Сергей, спасибо за ваш ответ! Я действительно ценю это! Я не пытался упростить этот код, так было в руководстве, я просто удалил пару полей, которые имели какое-либо значение. Я попробовал ваше решение, но получил некоторые ошибки компиляции, связанные с атрибутами InverseProperty. Я исправил ошибки, вот код, для которого я смог скомпилировать и сгенерировать миграцию: «
2. Извините, это была опечатка в моем ответе. Я не винил вас, чтобы упростить, я собирался упомянуть Microsoft. И я исправил еще одну опечатку. Вместо «Post.Blog» я набрал «Blog.Post». Теперь это исправлено. Вы можете проверить еще раз. Все должно работать правильно.
3. Вот код, для которого я смог скомпилировать и сгенерировать миграцию: « public partial class Blog { … [InverseProperty(«Blog»)] общедоступная виртуальная ICollection<Post> Сообщения { получить; установить; } … } открытый класс Post { … [InverseProperty(«Posts»)] общедоступный виртуальный блог Blog { get; set; } … } « Но, как я уже упоминал, это работало точно так же.
4. В вашем сообщении класса я не вижу [ForeignKey(nameof(BlogId))] это очень важно. без этого он не будет работать должным образом.
5. Длина комментария ограничена, поэтому я опустил части, которые точно такие же, как в вашем коде, включая ту часть, которую вы упомянули выше.