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。
我真的不是我的代码有什么问题。
我尝试使用现有实体 (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。