entity framework 再次插入现有的引用实体

entity framework inserting again an existing, referenced entity

我真的不是我的代码有什么问题。

我尝试使用现有实体 (Location) 并将其用作另一个实体的属性之一 (ApplicationUser)

我希望 ApplicationUser 引用现有的 Location,但它会创建一个新的 Location 并引用它。

以下是实体:

public class ApplicationUser : IdentityUser
{
    public int? LocationId { get; set; }
    public Location Location { get; set; } 
}


public class Location
{
    public Location()
    {
        this.Users = new HashSet<ApplicationUser>();
    }

    public int LocationId { get; set; }
    public string Country { get; set; }
    public string Province { get; set; }
    public string Area { get; set; }

    public virtual ICollection<ApplicationUser> Users { get; set; }
}

这是我的配置:

public class ApplicationUserConfiguration : EntityTypeConfiguration<ApplicationUser>
{
    public ApplicationUserConfiguration()
    {
        this.HasOptional(i => i.Location)
            .WithMany(i => i.Users)
            .HasForeignKey(i => i.LocationId);
    }
}

public class LocationConfiguration : EntityTypeConfiguration<Location>
{
    public LocationConfiguration()
    {
        this.HasKey(i => i.LocationId);
        this.Property(i => i.Country).HasMaxLength(100);
        this.Property(i => i.Province).HasMaxLength(100);
        this.Property(i => i.Area).HasMaxLength(100);
    }
}

以下是我保存位置的方法:

public Task SaveAsync(IUnitOfWork unitOfWork, Location entity)
{
        var context = (ApplicationDbContext)unitOfWork.Context;
        context.Entry(entity).State = entity.LocationId == 0
           ? EntityState.Added
           : EntityState.Modified;
        return context.SaveChangesAsync();
}

在我的代码中,我 pre-populate 首先是位置。 然后我调用一个现有位置作为用户的位置。

//successfully called an existing location. LocationId is 5
var adminLocation = await this._locationService.FindByArea("Philippines", "Laguna", "Calamba");

admin = new ApplicationUser
            {
               LockoutEnabled = false,
               Email = Settings.Default.DefaultAdminEmail,
               UserName = Settings.Default.DefaultAdminUserName,
               FirstName = "admin",
               LastName = "yow",

               // used here
               Location = adminLocation
             };

// save user
var identityResult = await this._userService.RegisterUserAsync(admin, 
    Settings.Default.DefaultAdminPassword);

执行后,检查数据库,得到如下图片。

我仍然想知道为什么它保存了一个新位置。 当我调试我的应用程序时,它在创建用户时没有调用位置保存方法。

是不是我的配置有问题? 谢谢大家。

位置Table:

用户 Table 使用了错误的位置:

它给你重复项,因为你设置了错误的字段。您应该使用要使用的 Location 记录的 ID 设置 LocationID 本身,而不是导航 属性。 EF这样做是因为它更关注ID,而不是导航属性上的ID。当它看到对象上存在 Location 记录,但看到 LocationID 为 0 时,它假定用户打算创建一个全新的 Location,因此将放置一个新的一个进入数据库。

这听起来很荒谬,我知道,但这就是适合您的 EF。

我写了一个博客 post 关于这个问题的更多信息 here