5

, 그것은 하나의 라인에서 이것을 설명하기 어렵다 : 사용자가이 외래 키 DefaultInvoiceAddressIdDefaultDeliveryAddressId을 가지고 있으며, UserAddress는 UserId 외국 키가 어디, 2 엔티티 UserUserAddress외래 키를 업데이트 한 후 참조 제약 조건이 일치하지 않는 이유는 무엇입니까? 성운 제목 죄송합니다

.

사용자 개체에는 기본 주소 (DefaultInvoiceAddressDefaultDeliveryAddress)에 대한 탐색 속성과 모든 주소 (AllAddresses)에 대한 탐색 속성이 있습니다.

매핑 등이 작동하여 사용자와 주소를 만들고 업데이트하는 것도 효과가 있습니다.

사용자의 기존 주소를 다음과 같이 설정하고 있지만 작동하지 않는 것은 무엇입니까? DefaultInvoiceAddress. SQL 용어로, 나는 무엇을하고 싶습니까 UPDATE USER SET DefaultInvoiceAddressId = 5 WHERE Id = 3입니다.

나는이에게 다음과 같은 방법을 시도했다 :

private void MarkAs(User user, UserAddress address, User.AddressType type) { 
     if (context.Entry(user).State == EntityState.Detached) 
      context.Users.Attach(user); 

     // guess I don't really need this: 
     if (context.Entry(address).State == EntityState.Detached) 
      context.UserAddresses.Attach(address); 

     if (type.HasFlag(User.AddressType.DefaultInvoice)) { 
      user.DefaultInvoiceAddressId = address.Id; 
      user.DefaultInvoiceAddress = null; 
      context.Entry(user).Property(u => u.DefaultInvoiceAddressId).IsModified = true; 
     } 

     if (type.HasFlag(User.AddressType.DefaultDelivery)) { 
      user.DefaultDeliveryAddressId = address.Id; 
      user.DefaultDeliveryAddress = null; 
      context.Entry(user).Property(u => u.DefaultDeliveryAddressId).IsModified = true; 
     } 
    } 

이 메소드가 불려 주소를 모두 업데이트 할 때뿐만 아니라 새로운 UserAddresses을 만들 때.

The changes to the database were committed successfully, 
but an error occurred while updating the object context. 
The ObjectContext might be in an inconsistent state. 
Inner exception message: A referential integrity constraint violation occurred: 
The property values that define the referential constraints are not consistent between principal and dependent objects in the relationship. 

은 내가 통해 함께로드 나는 데이터베이스에 포함 된 DefaultDeliveryAddress에서 PIN이 사용자 개체와 메서드를 호출 예상대로 만들 시나리오는 그러나 업데이트 경우에 나는 다음과 같은 오류가 발생 작품 열망하는 로딩. 간단히 말해서

var user = mainDb.User.Get(UnitTestData.Users.Martin.Id, User.Include.DefaultAddresses); 
var existingAddress = user.DefaultDeliveryAddress; 
mainDb.User.Addresses.SetAs(user, existingAddress, User.AddressType.DefaultInvoice)) 
// the SetAs method verfies input parameters, calls MarkAs and then SaveChanges 

, 난 그냥 쉽게 위의 SQL 업데이트 명령을 수행 할 것입니다 사용자도 자신의 DefaultInvoiceAddress의 DefaultDeliveryAddress을 만들고 싶어,하지만 난 내 EF 코드와 함께 뭔가가있어. 탐색 속성 ( DefaultInvoiceAddress)는이
  • UserAddress.UserId = User.Id (이미 할당되어 분명히 있기 때문에 null로 설정 한 재

    • 이 만 ID가 설정됩니다 은 이미 있음을 확인했습니다 속성 중 하나가 표시되지 않기 때문에 나는 또한 기본 주소를 모두 탐색 속성을 삭제하려
    • 수정 된 사용자 개체가 Modified 될 것
    • 사용자) (,) 디버거를 체크하지만
    • 도움이 중 하나를하지 않았다

    UserAddress에 대한 참조가 2 개있는 User 엔터티 때문에이 문제가 의심스럽고 두 개의 외래 키가 동일한 주소를 참조하도록 설정되어 있습니다. 어떻게 작동시킬 수 있습니까?

    업데이트 : 여기

    은 사용자 엔티티의 매핑은 다음과 같습니다

    // from UserMap.cs: 
    ... 
         Property(t => t.DefaultInvoiceAddressId).HasColumnName("DefaultInvoiceAddressId"); 
         Property(t => t.DefaultDeliveryAddressId).HasColumnName("DefaultDeliveryAddressId"); 
    
         // Relationships 
         HasOptional(t => t.DefaultInvoiceAddress) 
          .WithMany() 
          .HasForeignKey(t => t.DefaultInvoiceAddressId); 
    
         HasOptional(t => t.DefaultDeliveryAddress) 
          .WithMany() 
          .HasForeignKey(t => t.DefaultDeliveryAddressId); 
    
         HasMany(t => t.AllAddresses) 
          .WithRequired() 
          .HasForeignKey(t => t.UserId) 
          .WillCascadeOnDelete(); 
    

    UserAddress가 사용자로 다시 더 탐색 속성이 없습니다; 그것만이 HasMaxLength와 HasColumnName 설정을 contanis (나는 그들을 약간의 가독성을 유지하기 위해 제외시킨다).

    다음 업데이트 2

    는 Intellitrace에서 실행 된 명령입니다 :

    The command text "update [TestSchema].[User] 
    set [DefaultInvoiceAddressId] = @0 
    where ([Id] = @1) 
    " was executed on connection "Server=(localdb)\..." 
    

    나에게 잘 보이는; EF 상태 관리자 만 키 매핑으로 인해 혼란스러워합니다.

  • +0

    사용자 및 주소 정의 및 구성을 게시하십시오. 또한 생성 된 실제 SQL statemnts를 게시하십시오. –

    +0

    흠, SELECT는 단순히 쿼리에서 가져올 수 있지만 UPDATE/INSERT의 경우 SQL Mgmt 스튜디오 또는 프로필 (미니 프로파일 러는 한 번 볼 가치가 있음)이 필요합니다. –

    +0

    Intellitrace를 사용하여 명령문을 가져 오는 방법을 찾았습니다. 명령에 대한 내 질문을 업데이트했습니다. – enzi

    답변

    7

    문제를 알아 냈습니다. 분명히 EF가 의도 한 변경/업데이트로 해석 할 수 있기 때문에 탐색 속성을 null로 설정할 때 꽤 다른 점이 있습니다. (최소한 내가 의심하는 바입니다.)

    MarkAs 방법의 다음 버전은 작동합니다

    private void MarkAs(User user, UserAddress address, User.AddressType type) { 
         if (context.Entry(user).State == EntityState.Detached) { 
          // clear navigation properties before attaching the entity 
          user.DefaultInvoiceAddress = null; 
          user.DefaultDeliveryAddress = null; 
          context.Users.Attach(user); 
         } 
         // address doesn't have to be attached 
    
         if (type.HasFlag(User.AddressType.DefaultInvoice)) { 
          // previously I tried to clear the navigation property here 
          user.DefaultInvoiceAddressId = address.Id; 
          context.Entry(user).Property(u => u.DefaultInvoiceAddressId).IsModified = true; 
         } 
    
         if (type.HasFlag(User.AddressType.DefaultDelivery)) { 
          user.DefaultDeliveryAddressId = address.Id; 
          context.Entry(user).Property(u => u.DefaultDeliveryAddressId).IsModified = true; 
         } 
        } 
    

    미래의 독자들을 위해 내 연구 결과를 요약하면 :

    • 당신이 외래 키 속성을 통해 개체를 업데이트하려는 경우, 명확한 탐색 속성. EF는 업데이트 진술을 파악할 필요가 없습니다.
    • 내비게이션 등록 정보를 지우려면 전에 엔티티를 컨텍스트에 첨부해야합니다. 그렇지 않으면 EF가이를 변경으로 해석 할 수 있습니다. (내 경우에는 외래 키가 Nullable이며, 그렇지 않은 경우 EF는 네비게이션 속성 변경).

    다른 자격이있는 독자에게 답변 할 수있는 기회를 제공하기 위해 제 자신의 답변을 즉시 수락하지 않습니다. 다음 2 일 안에 답변이 게시되지 않으면이 질문에 동의합니다.