2009-01-15 9 views
20

2 संबंधित डेटाबेस तालिकाओं है बुला जो की तरह सरलीकृत प्रपत्र नज़र में इसLINQ एसक्यूएल के लिए: निष्पादन आदेश जब SubmitChanges()

Product(
    product_id, 
    name 
) 

ProductSpecs(
    spec_id, 
    product_id, 
    name, 
    value 
) 

विदेशी कुंजी product_id क्षेत्र के माध्यम से सेट किया गया है और ProductSpecs मेज पर एक अद्वितीय बाधा (है product_id, नाम) जोड़ी।

अब मेरे एएसपी.नेट एमवीसी अनुप्रयोग में जब उपयोगकर्ता उत्पाद चश्मा संपादित करता है और डेटा बचाता है तो मैं पुराने चश्मा हटा देता हूं और सभी को नए के रूप में सम्मिलित करता हूं।

मैं इसे पहली बार DataContext.DeleteAllOnSubmit() को कॉल करके करता हूं और पैरामीटर के रूप में वर्तमान (पुराना) उत्पादस्पेक्स प्रदान करता हूं, और फिर मैं उत्पाद में नए चश्मा जोड़ता हूं। उत्पाद स्पेक्स संग्रह।

फिर मैं DataContext.SubmitChanges() को कॉल करता हूं और एक त्रुटि प्राप्त करता हूं कि मेरी अनूठी बाधा का उल्लंघन किया गया था।

DataContenxt.GetChangeText() द्वारा दिए गए SQL कथनों को देखकर मैं देख सकता हूं कि INSERT को DELETEs से पहले निष्पादित किया गया है (भले ही मैंने AddAllOnSubmit() को पहले जोड़ा है)।

इस व्यवहार का कारण क्या है और इसे कैसे ठीक किया जाए या इसे कैसे हल किया जाए?

धन्यवाद।

+0

क्या आपने DeleteAllOnSubmit को कॉल करने के बाद सबमिटChanges() को कॉल करने का प्रयास किया है, लेकिन नए रिकॉर्ड जोड़ने से पहले? – RobS

+0

इससे पहले कि मैं यह सुनिश्चित कर सकूं कि नए रिकॉर्ड डाले जाएंगे जो गलत है, इससे पहले यह रिकॉर्ड हटा देगा। या सबमिटChanges() को कॉल करने के बाद भी रोलबैक करने का कोई तरीका है? –

+0

यदि आप डालने के लिए कोई नया रिकॉर्ड नहीं पाते हैं तो आप कॉल को एक लेन-देन और रोलबैक में लपेट सकते हैं। यद्यपि आप यह देखने के लिए जांच सकते हैं कि आपके पास हटाने से पहले नए रिकॉर्ड हैं या नहीं। – RobS

उत्तर

18

हाँ आखिरी चीज़ के रूप में सभी हटाएं। और इसे बदलने का कोई तरीका नहीं है।

या शायद वहां है। मैंने कोडजन डेटाकॉन्टेक्स्ट में यह देखने के लिए नहीं देखा है कि हम वहां कुछ ओवरराइड कर सकते हैं या नहीं।

आप जितनी बार चाहें SubmitChanges() को कॉल कर सकते हैं। जब मुझे पहली चीज़ के रूप में हटाने की ज़रूरत है, तो मेरा कामकाज, मेरे विलोपन को चिह्नित करता है, सबमिटChanges() को कॉल करता है, फिर आवेषण और अद्यतन करता है, और एक बार फिर सबमिटChanges को कॉल करें।

आप एक 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

मुझे यह समस्या भी हो रही है। मैं मैन्युअल रूप से प्रत्येक संभावित रूप से समस्या के लिए कुछ एसक्यूएल निष्पादित परिवर्तन 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

अचानक डाउनवॉट्स क्यों अचानक? इस जवाब को पोस्ट करने के 2 साल बाद! – Grokys

+2

शायद आप मैला गतिशील एसक्यूएल के लिए डाउनवॉट किया गया है। मैंने आपके स्कोर को 1 तक बढ़ा दिया है, लेकिन किसी को एसक्यूएल टेक्स्ट के साथ स्ट्रिंग कॉन्सटेनेशन का उपयोग कभी नहीं करना चाहिए, न कि यह एक खतरनाक आदत बन जाए। – DenNukem

+1

@ डेनुक्यूम: सच! पैरामीटर का उपयोग करने के लिए इसे बदल दिया, धन्यवाद! – Grokys

1

एक अन्य समाधान संलग्न करने के लिए है मैं इसे हल करने के लिए, मेरे लिए काम करने लगता है जो एक हैक के साथ आया था सही क्रम में किसी अन्य डेटा संदर्भ में परिवर्तन। हालांकि इस समाधान के नकारात्मक पक्ष यह है कि मूल डेटा संदर्भ से आपके शेष एप्लिकेशन से अभी भी संदर्भित किसी भी संस्था का अब अमान्य होगा :(

मैंने इस पर थोड़ा बदलाव करने की कोशिश की है, दूसरा अस्थायी डेटा बना रहा है प्रतिबद्ध के लिए संदर्भ। लेकिन मैं काम नहीं कैसे फिर एक साफ राज्य में मूल डेटा संदर्भ प्राप्त करने के लिए कर सकते हैं।

यह बहुत निराशा होती है, किसी कारण से, LINQ एसक्यूएल के लिए है :(

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

यह अब तक का सबसे सुंदर समाधान है। ओआरएम द्वारा उत्पन्न डेटा-संदर्भ भी आपके लिए इन आंशिक विधि स्टब्स बनाता है; यह संकेत देता है कि इस समाधान की संभावना है कि रचनाकारों को दिमाग में था। इसे और अधिक वोटों की जरूरत है। – Eric

संबंधित मुद्दे