एंटिटी फ्रेमवर्क 5 एक रिकॉर्ड अपडेट कर रहा है


870

मैं एक ASP.NET MVC3 वातावरण में इकाई फ्रेमवर्क 5 के भीतर एक रिकॉर्ड को संपादित / अद्यतन करने के विभिन्न तरीकों की खोज कर रहा हूं, लेकिन अभी तक उनमें से कोई भी सभी बक्से को टिक नहीं करता है जिनकी मुझे आवश्यकता है। मैं समझाता हूँ क्यों।

मुझे तीन विधियाँ मिली हैं जिनमें मैं पेशेवरों और विपक्षों का उल्लेख करूँगा:

विधि 1 - मूल रिकॉर्ड लोड करें, प्रत्येक गुण को अपडेट करें

var original = db.Users.Find(updatedUser.UserId);

if (original != null)
{
    original.BusinessEntityId = updatedUser.BusinessEntityId;
    original.Email = updatedUser.Email;
    original.EmployeeId = updatedUser.EmployeeId;
    original.Forename = updatedUser.Forename;
    original.Surname = updatedUser.Surname;
    original.Telephone = updatedUser.Telephone;
    original.Title = updatedUser.Title;
    original.Fax = updatedUser.Fax;
    original.ASPNetUserId = updatedUser.ASPNetUserId;
    db.SaveChanges();
}    

पेशेवरों

  • निर्दिष्ट कर सकते हैं कि कौन से गुण बदलते हैं
  • दृश्य में प्रत्येक संपत्ति शामिल करने की आवश्यकता नहीं है

विपक्ष

  • मूल लोड करने के लिए डेटाबेस पर 2 एक्स क्वेरी फिर इसे अपडेट करें

विधि 2 - मूल रिकॉर्ड लोड करें, परिवर्तित मान सेट करें

var original = db.Users.Find(updatedUser.UserId);

if (original != null)
{
    db.Entry(original).CurrentValues.SetValues(updatedUser);
    db.SaveChanges();
}

पेशेवरों

  • केवल संशोधित गुणों को डेटाबेस में भेजा जाता है

विपक्ष

  • दृश्य में प्रत्येक गुण सम्‍मिलित होना आवश्यक है
  • मूल लोड करने के लिए डेटाबेस पर 2 एक्स क्वेरी फिर इसे अपडेट करें

विधि 3 - अद्यतन रिकॉर्ड संलग्न करें और स्टेट को EntityState.Modified पर सेट करें

db.Users.Attach(updatedUser);
db.Entry(updatedUser).State = EntityState.Modified;
db.SaveChanges();

पेशेवरों

  • अद्यतन करने के लिए डेटाबेस पर 1 एक्स क्वेरी

विपक्ष

  • निर्दिष्ट नहीं कर सकते कि कौन से गुण बदलते हैं
  • दृश्य में प्रत्येक गुण होना चाहिए

सवाल

आप लोगों से मेरा सवाल; क्या कोई ऐसा साफ तरीका है कि मैं इस लक्ष्य को हासिल कर सकूं?

  • निर्दिष्ट कर सकते हैं कि कौन से गुण बदलते हैं
  • दृश्य में प्रत्येक प्रॉपर्टी (जैसे पासवर्ड!) होने की आवश्यकता नहीं है
  • अद्यतन करने के लिए डेटाबेस पर 1 एक्स क्वेरी

मैं समझता हूं कि यह इंगित करने के लिए काफी मामूली बात है लेकिन मुझे इसका एक सरल समाधान याद आ रहा है। यदि कोई विधि नहीं है, तो प्रबल हो जाएगा ;-)


13
ViewModels और एक अच्छे मैपिंग इंजन का उपयोग करें? आपको अपना दृष्टिकोण (और फिर अद्यतन करने के लिए) को पॉप्युलेट करने के लिए केवल "अपडेट करने के लिए गुण" मिलते हैं। अपडेट करने के लिए अभी भी 2 प्रश्न होंगे (मूल प्राप्त करें + इसे अपडेट करें), लेकिन मैं इसे "Con" नहीं कहूंगा। यदि यह आपकी एकमात्र प्रदर्शन समस्या है, तो आप एक खुश आदमी हैं;)
राफेल अल्तॉस

धन्यवाद @ RaphaëlAlthaus, बहुत वैध बिंदु। मैं ऐसा कर सकता था, लेकिन मुझे कई तालिकाओं के लिए CRUD ऑपरेशन बनाना है, इसलिए मैं एक ऐसी विधि की तलाश कर रहा हूं जो प्रत्येक मॉडल के लिए n-1 ViewModel बनाने के लिए मुझे सीधे मॉडल के साथ काम कर सके।
स्टैकआउट

3
खैर, मेरे वर्तमान प्रोजेक्ट में (कई इकाइयाँ भी) हमने मॉडल्स पर काम करने के साथ शुरू किया, यह सोचकर कि हम ViewModels के साथ काम करने में समय खो देंगे। अब हम ViewModels पर जा रहे हैं, और (नगण्य नहीं) बुनियादी ढाँचे पर काम शुरू कर रहे हैं, यह अब तक बहुत दूर, बहुत साफ और आसान है। और अधिक सुरक्षित (दुर्भावनापूर्ण "छिपे हुए खेतों" या उस तरह की चीजों के बारे में डरने की कोई ज़रूरत नहीं है)
राफेल अल्तॉस

1
और नहीं (भयानक) ViewBags अपने DropDownLists को आबाद करने के लिए (हमारे पास लगभग सभी CRU (D) के विचारों पर कम से कम एक DropDownList है ...)
Raphaël Althaus

मुझे लगता है कि आप सही हैं, ViewModels को अनदेखा करने की कोशिश करने के लिए मेरा बुरा। हां, ViewBag कई बार थोड़ा गंदा लगता है। मैं आमतौर पर डिनो एस्पोसिटो के ब्लॉग के अनुसार एक कदम आगे बढ़ता हूं और इनपुटमॉडल भी बनाता हूं, एक टैड बेल्ट और ब्रेसिज़ लेकिन यह काफी अच्छी तरह से काम करता है। बस प्रति मॉडल 2 अतिरिक्त मॉडल का अर्थ है - doh ;-)
स्टैकआउट

जवाबों:


681

आप क्या देख रहे हैं:

db.Users.Attach(updatedUser);
var entry = db.Entry(updatedUser);
entry.Property(e => e.Email).IsModified = true;
// other changed properties
db.SaveChanges();

59
hi @Ladislav Mrnka, यदि मैं एक ही बार में सभी संपत्तियों को अपडेट करना चाहता हूं, तो क्या मैं नीचे दिए गए कोड का उपयोग कर सकता हूं? db.Departments.Attach (विभाग); db.Entry (विभाग) .State = EntityState.Modified; db.SaveChanges ();
फ़ोयज़ुल करीम

23
@ खुश: हाँ, आप कर सकते हैं।
लादिस्लाव मृका

5
इस दृष्टिकोण के साथ समस्याओं में से एक यह है कि आप db.Entry () का मजाक नहीं उड़ा सकते, जो कि एक गंभीर PITA है। EF की कहीं-कहीं बहुत अच्छी कहानी है - यह बहुत कष्टप्रद है (जहाँ तक मैं बता सकता हूँ) उनके यहाँ एक नहीं है।
केन स्मिथ

23
@Foysal Doing reference.Entry (एंटिटी) .State = EntityState.Modified अकेले संलग्न करने के लिए पर्याप्त नहीं है। इसे स्वचालित रूप से इसके संशोधित रूप में संलग्न किया जाएगा ...
हैलोवर्ल्ड

4
@ Sandman4, इसका मतलब है कि हर दूसरी संपत्ति को वर्तमान मूल्य पर सेट होने की आवश्यकता है। कुछ एप्लिकेशन डिज़ाइनों में, यह संभव नहीं है।
दान एसपारज़ा

176

मुझे वास्तव में स्वीकृत उत्तर पसंद है। मेरा मानना ​​है कि इसके साथ ही एक और तरीका भी है। मान लीजिए कि आपके पास उन संपत्तियों की एक बहुत छोटी सूची है, जिन्हें आप कभी किसी दृश्य में शामिल नहीं करना चाहते हैं, इसलिए इकाई को अपडेट करते समय, उन्हें छोड़ दिया जाएगा। मान लीजिए कि वे दो क्षेत्र हैं पासवर्ड और एसएसएन।

db.Users.Attach(updatedUser);

var entry = db.Entry(updatedUser);
entry.State = EntityState.Modified;

entry.Property(e => e.Password).IsModified = false;
entry.Property(e => e.SSN).IsModified = false;   

db.SaveChanges();   

यह उदाहरण आपको अपने उपयोगकर्ता तालिका और अपने दृश्य में एक नया क्षेत्र जोड़ने के बाद अपने व्यापार तर्क को अनिवार्य रूप से अकेला छोड़ देता है।


यदि मुझे SSN संपत्ति के लिए कोई मूल्य निर्दिष्ट नहीं है, तब भी मुझे एक त्रुटि प्राप्त होगी, भले ही मैंने IsModified को गलत पर सेट किया हो, फिर भी यह मॉडल नियमों के विरुद्ध संपत्ति को मान्य करता है। इसलिए यदि संपत्ति को NULL के रूप में चिह्नित नहीं किया जाता है, तो यह विफल हो जाएगा अगर मैं किसी भी मूल्य को शून्य से अलग नहीं करता हूं।
रोलैंडसीसी सिप

आपको कोई त्रुटि नहीं मिलेगी क्योंकि वे फ़ील्ड आपके फॉर्म में नहीं होंगे। आप उन फ़ील्ड्स को छोड़ देते हैं, जिन्हें आप निश्चित रूप से अपडेट नहीं कर रहे हैं, डेटाबेस से प्रविष्टि को वापस संलग्न करके फ़ॉर्म का उपयोग करके हड़प लें, और प्रविष्टि को बताएं कि उन फ़ील्ड को संशोधित नहीं किया जा रहा है। मॉडल सत्यापन मॉडलस्ट्रेट में नियंत्रित होता है, संदर्भ में नहीं। यह उदाहरण एक मौजूदा उपयोगकर्ता को संदर्भित कर रहा है, इसलिए "अपडेट किया गया"। यदि आपका SSN एक आवश्यक फ़ील्ड है, तो यह तब होता है जब इसे पहली बार बनाया गया था।
एसएमडी

4
यदि मैं सही ढंग से समझता हूं, तो "updateUser" एक ऑब्जेक्ट का एक उदाहरण है जो पहले से ही FirstOrDefault () या समान के साथ आबादी वाला है, इसलिए मैं केवल उन गुणों को अपडेट कर रहा हूं जिन्हें मैंने बदल दिया है और दूसरों को ISModified = false पर सेट कर रहा है। यह ठीक काम करता है। लेकिन, जो मैं करने की कोशिश कर रहा हूं, वह यह है कि किसी ऑब्जेक्ट को पहले पॉप्युलेट किए बिना अपडेट किया जाए, बिना किसी भी FirstOrDefault () को अपडेट किए बिना। यह तब होता है जब मुझे कोई त्रुटि मिलती है यदि मैं सभी आवश्यक फ़ील्ड के लिए कोई मूल्य निर्दिष्ट नहीं करता हूं, यहां तक ​​कि उन गुणों पर भी मैंने ISModified = false सेट किया है। entry.Property (e => e.columnA) .IsModified = false; इस लाइन के बिना ColumnA असफल हो जाएगा।
रोलैंडसीसी

आप जो वर्णन कर रहे हैं वह एक नई इकाई बना रहा है। यह केवल अद्यतन करने के लिए लागू होता है।
smd

1
रोलैंडसीसी, डी.बी.ऑनफिगरेशन डाल दिया। db.SaveChanges () से पहले;
विल्की

28
foreach(PropertyInfo propertyInfo in original.GetType().GetProperties()) {
    if (propertyInfo.GetValue(updatedUser, null) == null)
        propertyInfo.SetValue(updatedUser, propertyInfo.GetValue(original, null), null);
}
db.Entry(original).CurrentValues.SetValues(updatedUser);
db.SaveChanges();

यह एक अच्छा समाधान की तरह लगता है - कोई मुस या उपद्रव नहीं; आपके पास गुणों को मैन्युअल रूप से निर्दिष्ट करने की आवश्यकता नहीं है और यह सभी ओपी गोलियों को ध्यान में रखता है - क्या कोई कारण है कि इसमें अधिक वोट नहीं हैं?
nocarrier

हालांकि यह नहीं है। इसमें एक सबसे बड़ा "विपक्ष" है, जो डेटाबेस में एक से अधिक हिट है। आपको इस उत्तर के साथ मूल लोड करना होगा।
smd

1
@smd आप यह क्यों कहते हैं कि यह डेटाबेस को एक से अधिक बार हिट करता है? जब तक SetValues ​​() का उपयोग नहीं होता है, तब तक मुझे ऐसा नहीं दिखाई देता, लेकिन ऐसा नहीं लगता कि यह सच होगा।
संसद

@ मुझे लगता है कि जब मैं ऐसा लिख ​​रहा हूँ तो मुझे नींद आ रही होगी। क्षमा याचना। वास्तविक समस्या एक अशक्त मूल्य से अधिक है। यदि अपडेट किए गए उपयोगकर्ता के पास अब किसी चीज़ का संदर्भ नहीं है, तो इसे साफ़ करने का मतलब है तो इसे मूल मूल्य से बदलना सही नहीं होगा।
smd

22

मैंने अपने रिपॉजिटरी बेस क्लास पर एक अतिरिक्त अपडेट विधि जोड़ी है जो स्कैफोल्डिंग द्वारा उत्पन्न अपडेट विधि के समान है। पूरे ऑब्जेक्ट को "संशोधित" करने के बजाय, यह व्यक्तिगत गुणों का एक सेट सेट करता है। (टी एक क्लास जेनेरिक पैरामीटर है।)

public void Update(T obj, params Expression<Func<T, object>>[] propertiesToUpdate)
{
    Context.Set<T>().Attach(obj);

    foreach (var p in propertiesToUpdate)
    {
        Context.Entry(obj).Property(p).IsModified = true;
    }
}

और फिर कॉल करने के लिए, उदाहरण के लिए:

public void UpdatePasswordAndEmail(long userId, string password, string email)
{
    var user = new User {UserId = userId, Password = password, Email = email};

    Update(user, u => u.Password, u => u.Email);

    Save();
}

मुझे डेटाबेस की एक यात्रा पसंद है। यह शायद देखने के मॉडल के साथ ऐसा करने के लिए बेहतर है, हालांकि, गुणों के दोहराव से बचने के लिए। मैंने अभी तक ऐसा नहीं किया है क्योंकि मैं नहीं जानता कि अपने डोमेन प्रोजेक्ट में मेरे विचार मॉडल सत्यापनकर्ताओं पर सत्यापन संदेश लाने से कैसे बचा जाए।


अहा ... व्यू मॉडल के लिए अलग प्रोजेक्ट और रिपॉजिटरी के लिए अलग प्रोजेक्ट जो व्यू मॉडल के साथ काम करते हैं।
इयान वॉर्बर्टन

11
public interface IRepository
{
    void Update<T>(T obj, params Expression<Func<T, object>>[] propertiesToUpdate) where T : class;
}

public class Repository : DbContext, IRepository
{
    public void Update<T>(T obj, params Expression<Func<T, object>>[] propertiesToUpdate) where T : class
    {
        Set<T>().Attach(obj);
        propertiesToUpdate.ToList().ForEach(p => Entry(obj).Property(p).IsModified = true);
        SaveChanges();
    }
}

क्यों न केवल DbContext.Attach (obj); DbContext.Entry (obj) .State = EntityState.Modified;
nelsontruran

यह setअपडेट स्टेटमेंट के हिस्से को नियंत्रित करता है ।
तनवीर बदर

4

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


3

आपके उपयोग के मामले के आधार पर, उपरोक्त सभी समाधान लागू होते हैं। यह है कि मैं आमतौर पर यह कैसे करते हैं:

सर्वर साइड कोड के लिए (जैसे एक बैच प्रक्रिया) मैं आमतौर पर संस्थाओं को लोड करता हूं और गतिशील परदे के पीछे काम करता हूं। आमतौर पर बैच प्रक्रियाओं में आपको सेवा के चलने के समय डेटा को लोड करने की आवश्यकता होती है। मैं कुछ समय बचाने के लिए खोज विधि का उपयोग करने के बजाय डेटा को बैचने का प्रयास करता हूं। इस प्रक्रिया के आधार पर मैं आशावादी या निराशावादी संगरोध नियंत्रण का उपयोग करता हूं (मैं हमेशा समानांतर निष्पादन परिदृश्यों को छोड़कर आशावादी का उपयोग करता हूं जहां मुझे सादे एसक्यूएल बयानों के साथ कुछ रिकॉर्ड लॉक करने की आवश्यकता होती है, हालांकि यह दुर्लभ है)। कोड और परिदृश्य के आधार पर प्रभाव को लगभग शून्य तक घटाया जा सकता है।

क्लाइंट साइड परिदृश्यों के लिए, आपके पास कुछ विकल्प हैं

  1. व्यू मॉडल का उपयोग करें। मॉडल में एक संपत्ति अपडेटस्टैटस (अनमोडिफाइड-डाला-अपडेट-डिलीट किया हुआ) होना चाहिए। उपयोगकर्ता के कार्यों (इन्सर्ट-अपडेट-डिलीट) के आधार पर इस कॉलम का सही मान सेट करना क्लाइंट की जिम्मेदारी है। सर्वर या तो मूल मूल्यों के लिए db क्वेरी कर सकता है या क्लाइंट को मूल मानों को परिवर्तित पंक्तियों के साथ सर्वर पर भेजना चाहिए। सर्वर को मूल मानों को संलग्न करना चाहिए और प्रत्येक पंक्ति के लिए UpdateStatus कॉलम का उपयोग करके यह तय करना चाहिए कि नए मूल्यों को कैसे संभालना है। इस परिदृश्य में मैं हमेशा आशावादी सहमति का उपयोग करता हूं। यह केवल इन्सर्ट - अपडेट - स्टेटमेंट्स को डिलीट करेगा और किसी भी सेलेक्ट को नहीं, लेकिन ग्राफ को चलाने और एंटिटीज को अपडेट करने के लिए कुछ चतुर कोड की आवश्यकता हो सकती है (आपके परिदृश्य पर निर्भर करता है - एप्लिकेशन)। एक मैपर मदद कर सकता है लेकिन CRUD लॉजिक को हैंडल नहीं करता है

  2. हवा की तरह एक पुस्तकालय का उपयोग करें। जेएस जो इस जटिलता को छुपाता है (जैसा कि 1 में वर्णित है) और इसे अपने उपयोग के मामले में फिट करने का प्रयास करें।

आशा है ये मदद करेगा

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.