2012-03-22 4 views
1

작업을 통해 양식에서 MVC 컨트롤러로 다시로드되는 개체가있는 상황이 있습니다. 우리는 FormCollection을 사용하지 않고 클래스를 직접 사용합니다.Entity Framework 4.3 컨트롤러 작업의 매개 변수에서 개체 첨부

[HttpPost] 
    public ActionResult AjaxUpdate(Customer customer) { ... 

Customer 개체에는 업데이트 된 것처럼 보이는 개체가 있는데, 컨텍스트에서 SaveDatabase()를 사용하면 단순히 작동하지 않습니다.

가 내가 작업에 사용했다 작동하려면 : 아직도

myDbContext.Customers.Attach(customer) 
//...Code here that set to the customer.SubObject a real object from the database so I am sure that the SubObject contain an id which is valid and the datacontext is aware of it... 
myDbContext.Entry(customer).State = EntityState.Modified; 

, 나는 관련된 예외했다 "스토어 업데이트, 삽입, 또는 문을 삭제 행의 예기치 않은 수의 영향 (0)" 내가 사용하여 제거 할 수 있었다 :

Database.ObjectContext().Refresh(RefreshMode.ClientWins,customer); 

그래서, 내 질문에, 을 휘게하는 이유 내가 +에 연결 상태 + 전화 새로 고침을 변경해야합니까. 다른 테이블에서 참조되는 개체를 포함하는 개체를 업데이트하는 더 좋은 방법은 없습니까? 코드 첫 번째 Entity Framework (Poco 개체)를 사용하고 있습니다. 또한 내 Databasecontext에서 숨겨져 있기 때문에 새로 고침을 사용하지 않습니다.

+0

또한 작업을 수행

따라서, 원래 하위 객체를로드에 대한 대체 솔루션 Customer에서 외래 키 속성을 소개하는 것입니다 주석 뒤에 숨겨진 코드를 제거 할 때 오류가 있습니까? 그렇지 않은 경우이 숨겨진 코드를보다 자세하게 스케치하는 것이 도움이 될 수 있습니다. 'Refresh'를 사용하여 객체 그래프의 작업 업데이트를 얻으려면 "정상이 아닙니다." – Slauma

+0

주석의 코드 (이 게시물에서 숨김)는이 하위 객체의 인스턴스를 고객에게 가져 오기 위해 하위 객체에 대한 쿼리입니다. 이는 클라이언트가 콤보 상자에서 새 값을 선택하고 데이터베이스에서 객체를 다시로드하여 고객에게 할당하므로 (고객의 FK를 업데이트하려는 목표로) 수행됩니다. –

+0

하위 객체를 가져 오는 데 'myDbContext'와 동일한 컨텍스트를 사용하고 있습니까? 'Customer' 클래스에 하위 객체에 대한 외래 키 속성이 있습니까? – Slauma

답변

2

EF 4.3.1로 콘솔 테스트 프로젝트를 만들었습니다. 코드는 내 생각에 주석 줄과 질문 아래에있는 의견 (내 추측은 프로그램이 사용자의 오류를 재현하지 않기 때문에 잘못된 것 같습니다) :

코드를 program.cs로 복사하고 EF 4.3.1에 대한 참조 추가 :

using System.Data; 
using System.Data.Entity; 

namespace EFUpdateTest 
{ 
    public class Customer 
    { 
     public int Id { get; set; } 
     public string Name { get; set; } 

     public int SubObjectId { get; set; } 
     public SubObject SubObject { get; set; } 
    } 

    public class SubObject 
    { 
     public int Id { get; set; } 
     public string Something { get; set; } 
    } 

    public class CustomerContext : DbContext 
    { 
     public DbSet<Customer> Customers { get; set; } 
     public DbSet<SubObject> SubObjects { get; set; } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      int customerId = 0; 
      int subObject1Id = 0; 
      int subObject2Id = 0; 
      using (var ctx = new CustomerContext()) 
      { 
       // Create customer with subobject 
       var customer = new Customer { Name = "John" }; 
       var subObject = new SubObject { Something = "SubObject 1" }; 
       customer.SubObject = subObject; 
       ctx.Customers.Add(customer); 

       // Create a second subobject, not related to any customer 
       var subObject2 = new SubObject { Something = "SubObject 2" }; 
       ctx.SubObjects.Add(subObject2); 

       ctx.SaveChanges(); 

       customerId = customer.Id; 
       subObject1Id = subObject.Id; 
       subObject2Id = subObject2.Id; 
      } 

      // New context, simulate detached scenario -> MVC action 
      using (var ctx = new CustomerContext()) 
      { 
       // Changed customer name 
       var customer = new Customer { Id = customerId, Name = "Jim" }; 
       ctx.Customers.Attach(customer); 

       // Changed reference to another subobject 
       var subObject2 = ctx.SubObjects.Find(subObject2Id); 
       customer.SubObject = subObject2; 

       ctx.Entry(customer).State = EntityState.Modified; 

       ctx.SaveChanges(); 
       // No exception here. 
      } 
     } 
    } 
} 

예외없이 작동합니다. 문제는 코드에서 오류를 일으킬 수있는 다른 점은 무엇입니까?

편집은 고객 클래스에서 외래 키 특성 SubObjectId이없는 댓글에

: 나는 오류를 재현 할 수 위의 나는 예제 프로그램의 속성을 제거합니다.

이 솔루션은 당신이 관계를 변경하기 전에 데이터베이스에서 원래 하위 객체를로드하는 것입니다 :

// Changed customer name 
var customer = new Customer { Id = customerId, Name = "Jim" }; 
ctx.Customers.Attach(customer); 

// Load original SubObject from database 
ctx.Entry(customer).Reference(c => c.SubObject).Load(); 

// Changed reference to another subobject 
var subObject2 = ctx.SubObjects.Find(subObject2Id); 
customer.SubObject = subObject2; 

ctx.Entry(customer).State = EntityState.Modified; 

ctx.SaveChanges(); 
// No exception here. 

외래 키 속성을하지 않고 당신이 독립 협회이 객체 모든 참조를 포함해야합니다 변경하기 전에 데이터베이스의 상태를 나타내야합니다. SubObject 참조를 customer으로 설정하지 않은 경우 EF는 데이터베이스의 원래 상태가 고객이 하위 개체를 참조하지 않는다고 가정합니다. UPDATE 문에 대한 생성 된 SQL이 같은 WHERE 절에 포함되어 고객이 조건이 충족되지 않은 DB [SubObject_Id]하지 NULL의 하위 객체를 가지고 있으며, UPDATE가 발생하지 않는 경우 (

WHERE [Customers].[Id] = 1 AND [Customers].[SubObject_Id] IS NULL 

또는 "예기치 않은 행 0"발생).

당신이 외래 키 속성이 경우에는 문제가 발생하지 않습니다 (외래 키 협회) :이 경우에 절은입니다 WHERE : 그래서

WHERE [Customers].[Id] = 1 

, 원래 무엇을 중요하지 않습니다 SubObjectSubObjectId입니다. 그럼에도 불구하고 null 값을 그대로두면 UPDATE가 작동합니다. 관계가 필요하지 않은 경우,

public int SubObjectId { get; set; } 

또는 :

public int? SubObjectId { get; set; } 
+0

Thx 나는 당신에게 +1을 준다. 비교해 볼게. 첫 모습에서 나는 당신이하는 일을 정확하게하고 있습니다. 유일한 차이점은 하위 객체는 PK가 아닌 EF에서 가져온 것이지만 다른 방법으로도 고유 한 코드에서 가져온 것입니다. 그러나 당신이 내게 준 것을 더 자세히 조사하게하겠습니다. –

+0

큰 차이점은 여기 있습니다. 당신은 SubObjectID를 위해 고객 내부의 ID를 사용합니다. 내부 예외가 아니라 예외가 있는지 확인하는 경우 : "관계의 외래 키 속성을 노출하지 않는 엔터티를 저장하는 동안 오류가 발생했습니다. EntityEntries 속성은 단일 엔터티를 예외 소스로 식별 할 수 없기 때문에 null을 반환합니다. 엔티티 타입에 외래 키 프로퍼티를 공개하면 저장시 예외 처리가보다 쉬워 질 수 있습니다. 자세한 내용은 InnerException을 참조하십시오. " –

+0

@PatrickDesjardins : 네 질문에 대한 마지막 코멘트에서 그렇게 말한 것은 네가 FK 속성을 가지고 있다고 가정하고 있었다. 나는 그것을 지금 제거하고 다시 시험했다. 이 테스트의 결과는 내 답변의 편집 섹션에 있습니다. – Slauma

관련 문제