2015-12-04 4 views
0

У меня есть контроллер API для написания новых пользователей в базу данных, которая выглядит следующим образом:Entity Framework код вопрос дублирования первого пункта

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 }))); 
    } 
} 

Когда я отладить этот метод и проверить user объект на

UserManager.Update(user); 

он имеет все свойства, установленные правильно, включая идентификаторы GUID типа пользователя, области, роли и розничных продавцов. Однако после выполнения строки и проверки моей базы данных пользователь, который был вставлен, имеет разные GUID для этих свойств, а EF вставил новые строки в таблицы типа пользователя и области, которые соответствуют моему новому пользователю.

Если удалить строку кода, который выполняет обновление и оставить линию

Repo.SaveChanges(); 

, то user правильно вставлена ​​с соответствующими идентификаторами типа пользователя и область, но строки, которые должны быть вставлены в моей DBO .UserRoles и dbo.UserRetailers не вставлены, что означает, что связь между пользователем и ролью/розничными продавцами, которые я ему назначил, потеряна.

Из моего исследования StackOverflow кажется, что объекты Area и User Type, которые я извлекаю из базы данных, отделяются от контекста, поэтому обновление создает новые объекты, которые имеют похожие свойства с теми, которые я выбрал, но (очевидно) с другим Id. Тем не менее, я все еще не уверен, как исправить эту проблему.

+0

Я не смотрел код, но из вашего описания проблемы кажется, что вы знаете, что вам нужно прикрепить объект к DbContext. Вот как вы можете это сделать: http://stackoverflow.com/a/29721938/1864167 Если это решает вашу проблему, дайте мне знать. –

ответ

0

После того, как мы справились с чем-то подобным с нашими сущностями, мы изменили все модели, чтобы всегда иметь идентификаторы, доступные для модели для отношений «Много-1», и всегда использовали управляемую таблицу для отношений «Множество-много», а не позволять сущности Framework обрабатывает его.

Затем мы обновили код, чтобы всегда применять идентификатор к модели, а не фактический другой объект.

Например:

Модели:

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 
    } 

Mapping:

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); 
     } 
    } 

Это обеспечивает все отображение будет сделано правильно, выставляет внешний ключ к вам, и позволяет создайте новый объект только с типом Id, а не с объектом полного типа.

Я считаю, что даже после SaveChanges() объект OrgType все еще может быть нулевым, однако в следующий раз вы получите его из контекста.

Это небольшая работа по изменению всего этого, но в конечном итоге доступ к основным/внешним ключам делает вещи намного проще.

Надеюсь, что это поможет!

+0

Спасибо за ваш ответ, я реорганизую свои модели соответственно. –

Смежные вопросы