添加包含另一个现有实体的新实体时的UWP efcore问题

时间:2017-09-27 07:11:59

标签: entity-framework uwp

我在UWP中遇到efcore问题。我想为每个请求使用一个DbContext,因为它似乎是使用efcore的最佳方式。但是当我尝试添加包含现有实体的新实体时,我的问题就出现了。例如: 我有一个包含帖子列表的博客。所以,帖子包含一个Blog实例。 假设我添加了一个博客。之后当我尝试添加一个新帖子并添加博客作为Blog时,我有一个SQLiteException:

  

SQLite错误19:'UNIQUE约束失败:Blogs.BlogId'

那么防止这个问题的最佳方法是什么?

我在github上发布了一个示例项目here

在此示例中,添加博客然后添加帖子,应该发生错误。

这是代码的最小部分:

博客模型:

class Post
{
    public int PostId { get; set; }
    public string Message { get; set; }

    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

发布模型:

class EfCoreTesterContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlite("Data Source=efcoretester.sqlite");
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<Post>()
            .HasOne(x => x.Blog)
            .WithMany(x => x.Posts)
            .HasForeignKey(x => x.BlogId);
    }
}

DbContext:

class DataAccessService
{
    #region Singleton

    public static DataAccessService Instance { get; } = new DataAccessService();

    #endregion

    #region Constructors

    private DataAccessService()
    {

    }

    #endregion

    #region Public methods

    public void AddBlog(Blog blog)
    {
        using (var db = new EfCoreTesterContext())
        {
            db.Add(blog);
            db.SaveChanges();
        }
    }

    public List<Blog> GetBlogs()
    {
        using (var db = new EfCoreTesterContext())
        {
            return db.Blogs.Include(x => x.Posts).ToList();
        }
    }

    public void AddPost(Post post)
    {
        using (var db = new EfCoreTesterContext())
        {
            db.Add(post);
            db.SaveChanges();
        }
    }

    public List<Post> GetPosts()
    {
        using (var db = new EfCoreTesterContext())
        {
            return db.Posts.ToList();
        }
    }

    #endregion
}

数据访问方法:

Asp.net

2 个答案:

答案 0 :(得分:3)

  

添加包含其他现有实体的新实体时的UWP efcore问题

根据您的代码段,该模型显示BlogPost之间的一对多关系。 Post是依赖实体,Blog是主体。

由于Post.BlogId是外键,因此当您要使用现有Post添加Blog实例时,应将现有Blog.BlogId添加到外键列拥有外键约束。因此,要添加包含现有Post的新Blog,您应该更新添加新的Post部分,如下所示:

private async void btnAddPost_Click(object sender, RoutedEventArgs e)
{
    if (!string.IsNullOrEmpty(txtPostMessage.Text))
    {
        Blog exsitblog = lvBlogs.SelectedItem as Blog;
        var newPost = new Post() { Message = txtPostMessage.Text, BlogId = exsitblog.BlogId }; 
        //var newPost = new Post() { Message = txtPostMessage.Text, Blog = lvBlogs.SelectedItem as Blog };
        DataAccessService.Instance.AddPost(newPost);
        txtPostMessage.Text = string.Empty;
        lvPosts.Items.Add(newPost);
    }
    else
    {
        MessageDialog dialog = new MessageDialog("Please enter post name");
        await dialog.ShowAsync();
    }
}

您的原始代码行用于创建一个引用了新Post实体的新Blog实体,以便在您向Blog表添加相同记录时抛出异常。添加新的Post时引用的新Blog应如下所示:

private async void btnAddPost_Click(object sender, RoutedEventArgs e)
{
    if (!string.IsNullOrEmpty(txtPostMessage.Text))
    { 
        Blog withnewblog = new Blog()
        {
            BlogId = 5,
            Name = "test"
        };
        var newPost = new Post() { Message = txtPostMessage.Text, Blog = withnewblog }; 
        DataAccessService.Instance.AddPost(newPost);
        txtPostMessage.Text = string.Empty;
        lvPosts.Items.Add(newPost);
    }
    else
    {
        MessageDialog dialog = new MessageDialog("Please enter post name");
        await dialog.ShowAsync();
    }
}

答案 1 :(得分:1)

对于您的后续问题,目前我们有三个表格,PersonBlogPostPersonPostBlogPost都是一对多的关系。如何添加记录?

在这种情况下,Post应包含两个外键。因此,由外键约束引起,每当您有一条新的Post记录时,您应该分配引用的Blog以及Person

为此,您可以考虑这一点,添加Blog条记录,然后添加Person条记录,现在我们可以依赖添加现有BlogId和{{1}的新帖子作为外键。

  

在这种情况下,是否有必要在Blog.Posts列表和Owner.Posts列表中添加我的新帖子?

因此,对于此问题,当您使用PersonId添加新帖时,您必须同时指定一个现有的Blog。并且您无法在没有存在Person的帖子中添加Blog,反之亦然。您不需要再次将帖子列表添加到引用的Person,因为您已经强制将它们分配给帖子。