如何将现有实体添加到EF中的新实体?

时间:2017-03-07 04:56:16

标签: asp.net-core-mvc entity-framework-core

我目前有2个相互映射的类。我收到以下错误:

  

MERGE语句与FOREIGN KEY约束冲突   " FK_Stories_Users_UserId&#34 ;.冲突发生在数据库中   " StoriesDb",table" dbo.Users",column' Id'。

我正在尝试将UserId FK添加到刚刚创建的新Story实体中。我的类看起来像这样(剪掉不相关的属性)

public class Story : ITimestamp
{
    public Story() {}

    public int Id { get; set; }

    public string Description { get; set; }
    public string DescriptionMarkdown { get; set; }
    public string Title { get; set; }
    public Guid UserId { get; set; }

    public virtual User User { get; set; }

    public virtual DateTime CreatedDate { get; set; }
    public virtual DateTime ModifiedDate { get; set; }
}    

public class User : ITimestamp
{
    public Guid Id { get; set; }
    public string Username { get; set; }
    public string Email { get; set; }
    public string PasswordHash { get; set; }
    public string PasswordSalt { get; set; }

    public virtual IList<Comment> Comments { get; set; } = new List<Comment>();
    public virtual DateTime CreatedDate { get; set; }
    public virtual DateTime ModifiedDate { get; set; }
}

我添加了这样的新故事:

public async Task<StorySummaryViewModel> Create(CreateViewModel model, string username, Guid userId)
{
      var story = await StoriesDbContext.Stories.AddAsync(new Story() {
                Title = model.Title,
                DescriptionMarkdown = model.DescriptionMarkdown,
                Description = CommonMarkConverter.Convert(model.DescriptionMarkdown),
                UserId = userId
      });

      var rowCount = await StoriesDbContext.SaveChangesAsync();
      [...]
}

通过其他一些Create方法,我知道将新实体对象添加到第二个新实体的导航属性将正确保存。但是,此时我不希望在保存Story实体时能够修改User实体,这就是我设置UserId属性(标记为FK)的原因。但它似乎没有起作用。

我还将传递给方法的UserId与数据库数据进行了比较,它们都是相同的值。

我在EF6中使用的只设置FK Id属性的技术可以按预期工作。

我是否在DbContext或我的映射中遗漏了一些内容,这些内容允许我通过外键ID来保存新实体?

这个问题与this StackOverflow question非常相似。但不幸的是,它只涉及新创建的实体。

修改 我包括我对故事和用户的映射。

public class StoryMap : IEntityTypeConfiguration<Story>
    {
        public void Map(EntityTypeBuilder<Story> builder)
        {
            builder.HasKey(e => e.Id);
            builder.Property(s => s.Url).IsRequired();
            builder.Property(s => s.Title).IsRequired();

            builder.HasOne(e => e.User).WithMany().HasForeignKey(e => e.UserId);
            builder.HasMany(e => e.Comments).WithOne(c => c.Story).HasForeignKey(c => c.StoryId);
            builder.HasMany(e => e.Votes).WithOne(v => v.Story).HasForeignKey(v => v.StoryId);
        }
    }

public class UserMap : IEntityTypeConfiguration<User>
{
    public void Map(EntityTypeBuilder<User> builder)
    {
        builder.HasKey(u => u.Id);
        builder.HasIndex(u => u.Email);

        builder.Property(u => u.PasswordHash).IsRequired();
        builder.Property(u => u.PasswordSalt).IsRequired();
        builder.Property(u => u.Username).IsRequired();
        builder.Property(u => u.Email).IsRequired();

        // Navigation
        [..snip..]
        builder.HasMany(u => u.Stories).WithOne(c => c.User).HasForeignKey(s => s.UserId);
    }
}

编辑迁移

migrationBuilder.CreateTable(
                name: "Stories",
                columns: table => new
                {
                    Id = table.Column<int>(nullable: false)
                        .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
                    CreatedDate = table.Column<DateTime>(nullable: false),
                    Description = table.Column<string>(nullable: true),
                    DescriptionMarkdown = table.Column<string>(nullable: true),
                    ModifiedDate = table.Column<DateTime>(nullable: false),
                    Title = table.Column<string>(nullable: false),
                    Url = table.Column<string>(nullable: false),
                    UserId = table.Column<Guid>(nullable: false),
                    UserIsAuthor = table.Column<bool>(nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Stories", x => x.Id);
                    table.ForeignKey(
                        name: "FK_Stories_Users_UserId",
                        column: x => x.UserId,
                        principalTable: "Users",
                        principalColumn: "Id",
                        onDelete: ReferentialAction.Restrict);
                });

1 个答案:

答案 0 :(得分:0)

我使用相同的技术(设置UserId值而不是完整的User引用)并且它正常工作,只有一个添加 - 我在UserId和{{1}之间使用显式FK绑定属性,像这样:

User

检查您的数据库(或迁移脚本) - 可能是EF在public Guid UserId { get; set; } [ForeignKey(nameof(UserId))] public virtual User User { get; set; } 中创建了两个不同的UserId类似的属性而没有此属性?

当然,如果您愿意,可以使用流畅的API代替属性。