2009-01-15 6 views
20

SubmitChanges()를 호출하는 등의 단순화 된 형태로 모양이Linq는 SQL로 : 실행하기 위해 나는이 개 관련 데이터베이스 테이블을

외래 키는 PRODUCT_ID 필드를 통해 설정 및 ProductSpecs 테이블에 고유 제한 조건을 (가지고있다

Product(
    product_id, 
    name 
) 

ProductSpecs(
    spec_id, 
    product_id, 
    name, 
    value 
) 
product_id, name) 쌍으로 구성됩니다.

내 ASP.NET MVC 응용 프로그램에서 사용자가 제품 사양을 편집하고 데이터를 저장하면 이전 사양이 삭제되고 새 사양으로 모두 삽입됩니다.

먼저 DataContext.DeleteAllOnSubmit()을 호출하고 현재 (이전) ProductSpec을 매개 변수로 제공 한 다음 Product.ProductSpecs 컬렉션에 새 사양을 추가합니다.

그런 다음 DataContext.SubmitChanges()를 호출하고 내 고유 제한 조건이 위반되었다는 오류를받습니다.

DataContenxt.GetChangeText()에서 반환 한 SQL 문을 보면 DELETE 전에 INSERT가 실행 된 것을 볼 수 있습니다 (추가하기 전에 DeleteAllOnSubmit()을 호출 했음에도 불구하고).

이 동작의 이유와 해결 방법이나 해결 방법은 무엇입니까?

감사합니다.

+0

DeleteAllOnSubmit을 호출 한 후 SubmitChanges()를 호출했지만 새 레코드를 추가하기 전에 시도한 적이 있습니까? – RobS

+0

이것은 새로운 레코드가 잘못 삽입되었는지 확실히 알기 전에 레코드를 삭제합니다. 또는 SubmitChanges() 호출 후에도 롤백 할 수 있습니까? –

+0

삽입 할 새 레코드가 없으면 트랜잭션 내부로 호출을 랩핑하고 롤백 할 수 있습니다. 삭제하기 전에 새 레코드가 있는지 확인할 수는 있지만 – RobS

답변

18

예 :(Linq에 매우 실망이다 마지막으로 모든 삭제를 수행하십시오. 변경할 방법이 없습니다.

또는 아마도있을 수 있습니다. 나는 codegen DataContext를 살펴보고 거기에 무언가를 오버라이드 할 수 있는지 살펴 보지 않았다.

원하는만큼 SubmitChanges()를 호출 할 수 있습니다. 첫 번째로 삭제해야 할 때 내 해결 방법은 내 삭제 표시, SubmitChanges() 호출, 삽입 및 업데이트 수행 및 SubmitChanges 호출입니다.

당신은 TransactionScope에 내부의 모든 것을 포장 할 수 있습니다

var deletables = 
     from toDelete in db.NamedValues 
     where toDelete.Name == knownValue.Name 
     select toDelete; 

    using (var scope = new TransactionScope()) 
    { 
     db.NamedValues.DeleteAllOnSubmit(deletables); 
     db.SubmitChanges(); 

     db.NamedValues.InsertOnSubmit(knownValue); 
     db.SubmitChanges(); 

     scope.Complete(); 
    } 
3

나는이 동일한 문제를 겪고 있습니다. 내가 수동으로 각 잠재적으로 문제에 대한 몇 가지 SQL을 실행 SubmitChanges()를 호출하기 전에 설정 변경에서 삭제 :

foreach (object o in m_Db.GetChangeSet().Deletes) 
{ 
    LibraryMember m = o as LibraryMember; 

    if (m != null) 
    { 
     m_Db.ExecuteCommand("DELETE FROM LibraryMembers WHERE LibraryMemberId={0}", m.LibraryMemberId); 
    } 
} 

m_Db.SubmitChanges() 
+0

왜 갑자기 downvotes가? 이 답변을 게시 한 지 2 년 후! – Grokys

+2

당신은 아마 엉성한 동적 SQL을 위해 downvoted가 있습니다. 귀하의 점수를 1로 올렸지 만 위험한 습관이되지 않도록 SQL 문과 문자열 연결을 절대로 사용하지 말아야합니다. – DenNukem

+1

@DenNukem : 사실! 매개 변수를 사용하도록 변경했습니다. 감사합니다. – Grokys

1

또 다른 방법 첨부하는 것입니다 나를 위해 작동하는 것 같다있는, 그것을 해결하기 위해 해킹 함께했다 올바른 순서로 다른 데이터 컨텍스트에 대한 변경. 그러나이 솔루션의 단점은 여전히 ​​원래 데이터 컨텍스트에서 나머지 응용 프로그램에서 참조 된 모든 엔터티가 이제 무효화됩니다. (

나는 약간의 변형을 시도하여 두 번째 임시 데이터 커밋에 대한 상황은.하지만 깨끗한 상태로 원래의 데이터 컨텍스트를 얻는 방법을 다음 작동하지 수 있습니다.

을 그것은 SQL을, 어떤 이유로,

public void Save() 
{ 
    string connectionString = m_Db.Connection.ConnectionString; 
    IList<object> deletes = m_Db.GetChangeSet().Deletes; 
    IList<object> inserts = m_Db.GetChangeSet().Inserts; 
    IList<object> updates = m_Db.GetChangeSet().Updates; 

    m_Db.Dispose(); 
    m_Db = new MyDataContext(connectionString); 

    Attach(m_Db, deletes); 
    m_Db.SubmitChanges(); 
    Attach(m_Db, updates); 
    m_Db.SubmitChanges(); 
    Attach(m_Db, inserts); 
    m_Db.SubmitChanges(); 
} 

void Attach(DataContext context, IList<object> items) 
{ 
    foreach (object o in items) 
    { 
     context.GetTable(o.GetType()).Attach(Clone(o)); 
    } 
} 

object Clone(object o) 
{ 
    object result = o.GetType().GetConstructor(Type.EmptyTypes).Invoke(null); 
    foreach (PropertyInfo property in o.GetType().GetProperties()) 
    { 
     if (property.PropertyType.IsValueType) 
     { 
      property.SetValue(result, property.GetValue(o, null), null); 
     } 
    } 
    return result; 
} 
0

을 대신 단지 모든 아이를 버리고 그들을 다시의, 좀 더 노력을 복용 고려하고 두 단계에서이 작업을 수행 : 항목을 추가하는 이전에 추가되었지만 더 이상 필요하지 않은 항목은 제거하고 제거하십시오. 예를 들어, ThinqLinq.com 사이트에는 범주에 지정할 수있는 게시물이 있습니다. 편집 화면에서 선택 및 선택 해제 할 수있는 범주 목록을 제공합니다.

Dim selectedCats() As String = CType(ValueProvider("categories").RawValue, String()) 
For Each catId In selectedCats.Except(From cp In currentPost.CategoryPosts _ 
             Select id = cp.CategoryID.ToString()) 
    'Add new categories 
    currentPost.CategoryPosts.Add(New CategoryPost With {.CategoryID = CInt(catId)}) 
Next 

'Delete removed categories 
dc.CategoryPosts.DeleteAllOnSubmit(From cp In currentPost.CategoryPosts _ 
            Where Not selectedCats.Contains(cp.CategoryID.ToString)) 
3

실체가 변경 한 내용을 사전에 알고 요구하지 않는 더 나은 솔루션이의 DataContext의의를 사용하는 것입니다 : 내가 선택한 카테고리의 목록이 포함 된 게시물을받을 때, 해당 레코드를 삭제하고 업데이트하려면 다음을 사용 삽입을 가로 채고 처음부터 삭제를 푸는 부분적인 메소드.

public partial class YourDataContext 
{ 
    List<EntityX> _deletedEntities = new List<EntityX>(); 

    partial void InsertEntityX(EntityX instance) 
    { 
     // Run deletes before inserts so that we don't run into any index violations 
     var deletes = 
      this.GetChangeSet().Deletes 
      .Where(d => d.GetType().Equals(instance.GetType())) 
      .Cast<EntityX>().ToList(); 

     var replaced = deletes.SingleOrDefault(d => d.UniqueKeyId == instance.UniqueKeyId); 

     if (replaced != null) 
     { 
      DeleteEntityX(replaced); 
      _deletedEntities.Add(replaced); 
     } 

     this.ExecuteDynamicInsert(instance); 
    } 

    partial void DeleteEntityX(EntityX instance) 
    { 
     if (_deletedEntities.Contains(instance)) 
     { 
      _deletedEntities.Remove(instance); 
      return; 
     } 

     this.ExecuteDynamicDelete(instance); 
    } 
} 
+0

이것은 가장 우아한 해결책입니다. ORM에 의해 생성 된 데이터 컨텍스트는 이러한 부분 메소드 스텁을 생성합니다. 이것은이 솔루션이 제작자가 염두에 두었을 가능성이 있음을 암시합니다. 이것은 더 많은 득표를 필요로합니다. – Eric

관련 문제