2014-07-17 2 views
0

매핑 된 테이블을 사용하여 MenuItem을 IdentityRole에 매핑하여 로그인 된 사용자 역할을 기반으로 메뉴를 만들 수있는 코드가있는 첫 번째 모델이 있습니다. 할당.Entity Framework 6 - 외부 키 IdentityRole을 가진 엔티티를 추가하는 방법

public class MenuItem 
{ 
    public int Id { get; set; } 
    public string Text { get; set; } 
} 

public class MenuRoleMap 
{ 
    [Key] 
    public int Id { get; set; } 

    public virtual MenuItem MenuItem { get; set; } 
    public virtual IdentityRole Role { get; set; } 
} 

IdentityRole과 정체성의 나머지는이 같은 내 ApplicationDbContext을 통해 상속 한 IdentityDbContext를 통해 자동으로 연결되어, 다음 컨텍스트가 일치해야합니다.

public class ApplicationDbContext : IdentityDbContext<User> 

테이블의 모든

들이 예상 열과 외래 키를 바로보고, 여기에 MenuRoleMap 테이블 table MenuRoleMap

이다 나는 내가 사용하는 MenuItem을하고 IdentityRole의 유효한 기존 인스턴스가 시도하고이 오류가 발생합니다이 테이블

foreach (IdentityRole role in selectedRoles) 
{ 
    MenuRoleMap mrm = new MenuRoleMap(); 
       mrm.MenuItem = menuItem; 
       mrm.Role = role; 
       db.MenuRoleMaps.Add(mrm); 
} 
db.SaveChanges(); /// <<<=== HERE ERROR BECAUSE THE role IS ALREADY IN DB 

에 새 개체 항목을 추가하는

A first chance exception of type 'System.Data.Entity.Validation.DbEntityValidationException' occurred in EntityFramework.dll 
Role: Role SystemsAdministrator already exists. 

당연히 그것이 존재한다는 것은 알고 있습니다. 이미 데이터베이스에 있습니다. EF는 이미 존재하는 경우 외래 키 엔티티에 대한 새로운 엔티티 항목을 추가하려고해서는 안됩니다.

MenuItem의 경우 IdentityRole에만 적용됩니다.

은 내가 IdentityRole 프록시 객체가 된 이후 문제가 프록시 생성 알았는데, 그래서 나는
this.Configuration.ProxyCreationEnabled = false; 

을이 꺼져하지만 난 여전히 같은 오류가 발생합니다.

제 질문은 외래 키가 IdentityRole 인 엔터티를 어떻게 추가합니까?

스태커에게 감사드립니다. 문제는 상황 자체가 하나를 제외한 객체의 유효성이 아니었다 다양한 솔루션을 조사하는 동안 아래 사람들의 도움 후 내 자신의 질문

TO


답을 발견했다. 그 대상은 옳았다. 내가 깨닫지 못했던 것은 그것이 맥락에서 나온 대상이 아니라는 것이다. 그것은 팩시밀리였다. 이 팩시밀리를 모델에 추가하려고하면 컨텍스트에서 이미 존재한다고 말하고 다시 추가 할 수는 없습니다. 아이템의 상태를 오버라이드 (override)하려고하면 (자), 다른 종류의 에러가 발생했습니다.

해상도

는 헤이 프레스토 모든 일을 컨텍스트에서 개체를 다시로드하고 그래서

foreach (IdentityRole role in selectedRoles) 
{ 
    // Here I'm getting the role from the context using the ID I have from the facsimile 
    IdentityRole roleToUse = db.Roles.Where(x => x.Id == role.Id).FirstOrDefault(); 
    // carry on as normal 
    MenuRoleMap mrm = new MenuRoleMap(); 
    mrm.MenuItem = menuItem; 
    mrm.Role = roleToUse; // note I'm using the retrieved 'roleToUse' 
    db.MenuRoleMaps.Add(mrm); 
} 
db.SaveChanges(); 

처럼 부모 항목이 추가 단순히이었다.

+0

선택한 역할은 다음과 같은 컨텍스트에서 제공됩니다. ApplicationDbContext db = ApplicationDbContext.Create(); List selectedRoles = db.Roles.ToList(); – AndyM

+0

'role'은 db.Entry (role) .State = Detached를 말합니다. 동일한 컨텍스트 내의 'menuItem'이 State = Unchanged (사실임)라는 것을 알 수 있듯이 두 항목 모두 변경되지 않을 것으로 기대합니다. – AndyM

+0

죄송합니다. 다른 컨텍스트에 대한 참조를 만들었지 만 실제로는 ApplicationDbContext : IdentityDbContext 과 동일합니다. 이것은 MVC 프로젝트입니다.이 인스턴스에서 컨트롤러는 역할을 검색하는 메소드에 컨텍스트를 전달합니다.이 경우 컨텍스트가 동일하다고 생각합니다. – AndyM

답변

2

다른 컨텍스트에서 엔터티를 검색 한 다음이를 해당 컨텍스트에 추가 된 엔터티에 할당 한 것처럼 보입니다. 그런 다음 Role 엔티티도 삽입하려고 시도합니다.

컨텍스트의 유효 기간이 다른 메서드에서 해당 메서드로 롤을 반환합니까?

당신은 객체의 상태를 업데이트에 관해서 유용한 다음 링크를 찾을 수 있습니다 : Entity states and SaveChanges

+0

고마워, 나는 Entity State를 'Added'로 수동 설정하려고 시도했지만 동일한 오류가 발생한다. 이 방식에 접근하는 방법은 항상 EntityRole을 만들려고합니다. 볼 수 없거나 잘못된 방식으로 EntityRole을 사용하고있는 것처럼 보입니다. 어떤 이유로 든 직접 액세스 할 수 있습니다. – AndyM

+0

삽입을 방지하기 위해 추가 대신에 'db.Entry (Role) .State = EntityState.Unchanged'를 사용하여 상태를 설정하고자 할 것입니다. 기본적으로 EF는 명시 적으로 말하지 않는 한 새 오브젝트가 무엇인지 또는 기존 오브젝트인지 알지 못하지만 작업중인 오브젝트로 다른 오브젝트에서 검색된 오브젝트에 대해서만이를 수행하면됩니다. 컨텍스트 자체가 변경 내용을 추적합니다. 'SaveChanges' 전에 디버깅하는 동안'db.ChangeTracker.Entries()'를 실행하면 컨텍스트가 DB에 할 변경 사항을 볼 수 있습니다. – user978139

+0

내 이전 답변에 더하여, 이제는 '역할'처럼 보이는 개체를 '역할'이라고 가정하는 내 어리 석음을 밝혀야하며 당연히 그렇지 않습니다. 따라서 문맥은 같지만 객체는 동일하지 않습니다. 이미 가지고있는 ID를 사용하여 'role'객체를 다시 검색하면 해결됩니다. 문제가 해결되었습니다. 덕분입니다. – AndyM

0

문제는 당신이 사용하는 경우 db.Set<MyEntity>.Add는 것으로 추가되는 개체에 연결된 모든 개체를 표시하는 것입니다 덧붙였다. 명시 적으로 변경되지 않은 것으로 표시해야합니다.

foreach (IdentityRole role in selectedRoles) 
{ 
    MenuRoleMap mrm = new MenuRoleMap(); 
       mrm.MenuItem = menuItem; 
       mrm.Role = role; 
       db.MenuRoleMaps.Add(mrm); 
       db.Entry(role).State=EntityState.Unchanged; 
} 
db.SaveChanges(); 
+0

물론 그 작업을 수행 할 수 있지만 변경 사항을 저장할 때 문제가 발생합니다. – Dabblernl

0

내 대답은 할 수 없거나 적어도해서는 안됩니다.

인증 (역할) 및 비즈니스 (메뉴)는 응용 프로그램의 다른 관심사입니다.

내게 필요한 IdentityDb 부분 인 ApplicationDb를 가져 와서 동기화를 구성해야합니다.

설명 : Google 또는 LiveID를 인증 공급자로 사용하는 이미징 : ApplicationDd에서 Google 또는 Microsoft Dbs로 네비게이션 속성을 상상할 수 있습니까?

분명히 아닙니다.

인증 데이터베이스의 역할을 복제하는 AppRole을 만들고 응용 프로그램 데이터베이스에서이 테이블을 사용하여 메뉴를 작성하십시오. 또 다른 솔루션은 응용 프로그램 및 신원에 대한 동일한 컨텍스트를 사용하는 것입니다

List<Int32> l = IdentityContext.GetRolesForUser(currentUserId); 
foreach (AppRole role in AppContext.Roles.Where(r => l.Contains(r.Id))) 
{ 
    MenuRoleMap mrm = new MenuRoleMap(); 
      mrm.MenuItem = menuItem; 
      mrm.Role = role; 
      appContext.MenuRoleMaps.Add(mrm); 
} 
appContext.SaveChanges(); 

: 같은

의사 코드에서이 보인다.

컨텍스트의 상속은 괜찮은 것처럼 보이지만 결코 테스트하지 않았습니다.

+0

저는 컨텍스트가 항상 같고 오브젝트의 상태를 보았습니다. 'role'의 상태를 Unchanged로 설정하면 도움이되지 않습니다. 다른 오류가 발생합니다. 이번에는 키 충돌이 발생합니다. . 나는 이것을 _Authentication (Roles)과 Business (Menu)가 application의 다른 관심사라는 @ tschmit007의 주장을 받아 들인다는 근거로 대답으로 받아 들인다. – AndyM

관련 문제