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
, 원래 무엇을 중요하지 않습니다 SubObject
및 SubObjectId
입니다. 그럼에도 불구하고 null
값을 그대로두면 UPDATE가 작동합니다. 관계가 필요하지 않은 경우,
public int SubObjectId { get; set; }
또는 :
public int? SubObjectId { get; set; }
또한 작업을 수행
따라서, 원래 하위 객체를로드에 대한 대체 솔루션
Customer
에서 외래 키 속성을 소개하는 것입니다 주석 뒤에 숨겨진 코드를 제거 할 때 오류가 있습니까? 그렇지 않은 경우이 숨겨진 코드를보다 자세하게 스케치하는 것이 도움이 될 수 있습니다. 'Refresh'를 사용하여 객체 그래프의 작업 업데이트를 얻으려면 "정상이 아닙니다." – Slauma주석의 코드 (이 게시물에서 숨김)는이 하위 객체의 인스턴스를 고객에게 가져 오기 위해 하위 객체에 대한 쿼리입니다. 이는 클라이언트가 콤보 상자에서 새 값을 선택하고 데이터베이스에서 객체를 다시로드하여 고객에게 할당하므로 (고객의 FK를 업데이트하려는 목표로) 수행됩니다. –
하위 객체를 가져 오는 데 'myDbContext'와 동일한 컨텍스트를 사용하고 있습니까? 'Customer' 클래스에 하위 객체에 대한 외래 키 속성이 있습니까? – Slauma