C# 实体框架代码第一项重复问题
我有一个API控制器,用于将新用户写入数据库,如下所示:C# 实体框架代码第一项重复问题,c#,sql,entity-framework,ef-code-first,code-first,C#,Sql,Entity Framework,Ef Code First,Code First,我有一个API控制器,用于将新用户写入数据库,如下所示: public abstract class ApiBaseController : ApiController { protected UserManager<User, Guid> UserManager { get; set; } protected dbcontext Repo { get; private set; } public ApiBaseController()
public abstract class ApiBaseController : ApiController
{
protected UserManager<User, Guid> UserManager { get; set; }
protected dbcontext Repo { get; private set; }
public ApiBaseController()
{
UserManager = HttpContext.Current.GetOwinContext().GetUserManager<XUserManager>();
Repo = HttpContext.Current.GetOwinContext().Get<dbcontext>();
}
}
public class UsersController : ApiBaseController
{
[HttpPost]
[FeatureAuthorization(FeatureName = "Users", Permission = FeaturePermissions.Write)]
public IHttpActionResult Post([FromBody]CreateUserRequest req)
{
if (!ModelState.IsValid)
{
return ResponseMessage(Request.CreateResponse(HttpStatusCode.BadRequest, ModelState.ToApiResponse()));
}
var user = UserManager.FindByName(req.UserName);
//some validation happens here
user = new User()
{
AuthenticationMethod = req.AuthenticationMethod,
DomainLDAP = req.DomainLDAP,
EmailAddress = req.EmailAddress,
FirstName = req.FirstName,
SecondName = req.SecondName,
MentionHandle = req.MentionHandle,
MobileNumber = req.MobileNumber,
UserName = req.UserName,
IsDeleted = false
};
IdentityResult createResult = null;
if (req.AuthenticationMethod == AuthenticationMethod.Internal)
{
createResult = UserManager.Create(user);
}
else
{
createResult = UserManager.Create(user, req.Password);
}
if (!createResult.Succeeded)
{
return ResponseMessage(Request.CreateResponse(HttpStatusCode.BadRequest, new ApiResponse(createResult.Errors.ToArray())));
}
//Map user to user type
user.UserType = Repo.UserTypes.Find(req.UserTypeId);
//Map user to area
user.Area = Repo.Areas.Find(req.AreaId);
//Map user to role
var roles = new List<Role>();
roles.Add(role);
user.Roles = roles;
//Map user to retailers
user.Retailers = retailers;
UserManager.Update(user);
Repo.SaveChanges();
var dto = Mapper.Map<UserDto>(user);
return ResponseMessage(Request.CreateResponse(HttpStatusCode.Created, new ApiResponse<UserDto>(new[] { dto })));
}
}
它正确设置了所有属性,包括用户类型、区域、角色和零售商的GUID。但是,在执行该行并检查我的数据库之后,插入的用户对于这些属性具有不同的guid,并且EF已将新行插入到与我的新用户对应的用户类型和区域表中
如果我删除执行更新的代码行并保留
Repo.SaveChanges();
行中,用户
使用适当的用户类型和区域ID正确插入,但是没有插入应该插入到我的dbo.UserRoles和dbo.UserRetailers桥接表中的行,这意味着用户和我分配给它的角色/零售商之间的链接丢失
根据我对StackOverflow的研究,我从数据库中获取的区域和用户类型对象似乎与上下文分离,因此更新创建的新对象与我获取的对象具有相似的属性,但(显然)具有不同的Id。然而,我仍然不知道如何解决这个问题。在处理了与实体类似的问题后,我们更改了所有模型,使其在多对1关系的模型上始终具有可用的ID,并始终对多对多关系使用托管表,而不是让实体框架处理它 然后,我们更新了代码,使其始终将ID应用于模型,而不是实际的其他对象 例如: 型号:
public class Organisation
{
public Guid Id { get; set; }
public String Name { get; set; }
public String Description { get; set; }
//etc etc
public Guid OrgTypeId { get; set; }
#region Navigation properties
public virtual OrgType OrgType { get; set; }
#endregion
}
public class OrgType
{
public Guid Id { get; set; }
public String Name { get; set; }
public string Description { get; set; }
#region Navigation properties
public virtual ICollection<Organisation> Organisations { get; set; }
#endregion
}
公共类组织
{
公共Guid Id{get;set;}
公共字符串名称{get;set;}
公共字符串说明{get;set;}
//等等
公共Guid OrgTypeId{get;set;}
#区域导航属性
公共虚拟组织类型组织类型{get;set;}
#端区
}
公共类组织类型
{
公共Guid Id{get;set;}
公共字符串名称{get;set;}
公共字符串说明{get;set;}
#区域导航属性
公共虚拟ICollection组织{get;set;}
#端区
}
映射:
public class OrganisationMap : EntityTypeConfiguration<Organisation>
{
public OrganisationMap()
{
HasKey(t=>t.Id);
Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(t => t.Name).HasMaxLength(256);
Property(t => t.Description).IsMaxLength().HasColumnType("ntext");
HasRequired(t => t.OrgType).WithMany(t => t.Organisations).HasForeignKey(t => t.OrgTypeId);
}
}
公共类组织图:EntityTypeConfiguration
{
公共组织地图()
{
HasKey(t=>t.Id);
属性(t=>t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
属性(t=>t.Name).HasMaxLength(256);
属性(t=>t.Description).IsMaxLength().HasColumnType(“ntext”);
HasRequired(t=>t.OrgType)。有许多(t=>t.OrgType)。HasForeignKey(t=>t.OrgTypeId);
}
}
这将确保所有映射都正确完成,向您公开外键,并允许您仅使用类型Id而不是完整类型对象创建新对象
但是,我相信即使在SaveChanges()之后,OrgType对象也可能仍然为null,不过下次从上下文中获取它时就可以了
改变这一切需要做一些工作,但从长远来看,访问主键/外键会使事情变得更容易
希望有帮助 我没有看过代码,但是从您的问题描述来看,似乎您知道必须将对象附加到DbContext。你可以这样做:如果这解决了你的问题,让我知道。谢谢你的回复,我会相应地重构我的模型。
public class OrganisationMap : EntityTypeConfiguration<Organisation>
{
public OrganisationMap()
{
HasKey(t=>t.Id);
Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(t => t.Name).HasMaxLength(256);
Property(t => t.Description).IsMaxLength().HasColumnType("ntext");
HasRequired(t => t.OrgType).WithMany(t => t.Organisations).HasForeignKey(t => t.OrgTypeId);
}
}