एंटिटी फ्रेमवर्क में अपडेट पर संपत्ति को छोड़ दें


79

मैं MVC में एक मॉडल को अपडेट करते समय परिवर्तित नहीं होने के लिए एक संपत्ति को चिह्नित करने के लिए उचित तरीके की तलाश कर रहा हूं

उदाहरण के लिए, आइए इस छोटे मॉडल को लें:

class Model
{
    [Key]
    public Guid Id {get; set;}
    public Guid Token {get; set;}

    //... lots of properties here ...
}

तब MVC बनाने की विधि इस तरह दिखाई देती है:

[HttpPost]
public ActionResult Edit(Model model)
{
    if (ModelState.IsValid)
    {
        db.Entry(model).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(model);
}

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

मैं कुछ इस तरह की तलाश में हूँ:

db.Entry(model).State = EntityState.Modified;
db.Entry(model).Property(x => x.Token).State = PropertyState.Unmodified;
db.SaveChanges();

अब तक मैंने जो सबसे अच्छा तरीका पाया है, वह समावेशी है और सभी संपत्तियों को सेट करना चाहता हूं, जिन्हें मैं हाथ से शामिल करना चाहता हूं, लेकिन मैं वास्तव में केवल यह कहना चाहता हूं कि किन लोगों को बाहर रखा जाना है।


संभावित डुप्लिकेट: stackoverflow.com/questions/3809583/…
Nate-Wilkins

मुझे नहीं लगता कि यह डुप्लिकेट है: मैं हमेशा एक निश्चित संपत्ति को बिल्कुल अद्यतन होने से बाहर रखना चाहता हूं । उपयोगकर्ता को इसे बदलने की कोई क्षमता नहीं होनी चाहिए।
मैनुअल श्वेगर्ट सेप

2
आप viewmodels का उपयोग कर सकते हैं और सिर्फ वही मैप कर सकते हैं जिसे आप अपडेट करना चाहते हैं।
frennky

मैं कर सकता। इस मुद्दे के आसपास कुछ तरीके हैं । लेकिन मैं यह जानना चाहता हूं कि क्या ऐसा करने का अच्छा तरीका है, और अगर एक है, तो यह कैसे काम करता है। btw, सबसे छोटा "समाधान" मुझे इस एटीएम में एक और लेनदेन खोलना है: using (var db2 = new DataContext()) model.Token = db2.Models.Find(model.Id).Token;लेकिन मैं इस एक के साथ खुश नहीं हूं।
मैनुअल शूवेगर्ट

3
मैं स्वीकार करता हूं कि ऐसा करने का यह "उचित" तरीका है, लेकिन इसे इस तरह से नहीं करने के लिए कारण हैं: ए) ओवरहेड, बी) फुर्तीली नहीं, सी) अचूक / त्रुटि प्रवण। तो हाँ, मैं एक संपत्ति को छोड़कर दो समान कक्षाएं बनाने से इनकार करता हूं।
मैनुअल शूवेगर्ट

जवाबों:


156

हम इस तरह का उपयोग कर सकते हैं

 db.Entry(model).State = EntityState.Modified;
 db.Entry(model).Property(x => x.Token).IsModified = false;
 db.SaveChanges();

यह अद्यतन करेगा लेकिन टोकन संपत्ति के बिना


2
यदि आप उपयोग कर रहे हैं तो क्या होगा AddOrUpdate? - आप कैसे उपयोग करना जानते हैं EntityState.Modifiedया EntityState.Added?
जेस

1
अद्यतन: इसे EF 6 में काम करने के लिए .. आपको db.Model.Attach (मॉडल) की आवश्यकता है;
मैक्सी

6
बस दूसरों को ध्यान दें कि यहां ऑर्डर महत्वपूर्ण है: यदि आप सेट करने के db.Entry(model).State = EntityState.Modified;बाद सेट db.Entry(model).Property(x => x.Token).IsModified = false; करते हैं, तो संपत्ति को बचाने पर अपडेट किया जाएगा।
एकरा

1
और यह भी मॉडल मानों को अद्यतन करने के बाद होना चाहिए db.Entry (मॉडल) ।CurrentValues.SetValues ​​(sourceModel); यदि नहीं, तो संपत्ति को बचाने पर भी अपडेट किया जाता है।
डॉटनेट फैन

10

नया मॉडल बनाएं जिसमें सीमित संख्या में गुण हों जिन्हें आप अपडेट करना चाहते हैं।

यानी यदि आपका इकाई मॉडल है:

public class User
{
    public int Id {get;set;}
    public string Name {get;set;}
    public bool Enabled {get;set;}
}

आप कस्टम व्यू मॉडल बना सकते हैं जो उपयोगकर्ता को नाम बदलने की अनुमति देगा, लेकिन सक्षम ध्वज नहीं:

public class UserProfileModel
{
   public int Id {get;set;}
   public string Name {get;set;}
}

जब आप डेटाबेस अपडेट करना चाहते हैं, तो आप निम्न कार्य करते हैं:

YourUpdateMethod(UserProfileModel model)
{
    using(YourContext ctx = new YourContext())
    { 
        User user = new User { Id = model.Id } ;   /// stub model, only has Id
        ctx.Users.Attach(user); /// track your stub model
        ctx.Entry(user).CurrentValues.SetValues(model); /// reflection
        ctx.SaveChanges();
    }
}

जब आप इस विधि को कॉल करते हैं, तो आप नाम को अपडेट कर देंगे, लेकिन सक्षम संपत्ति अपरिवर्तित रहेगी। मैंने सरल मॉडल का उपयोग किया है, लेकिन मुझे लगता है कि आपको चित्र का उपयोग करना होगा।


धन्यवाद, यह अच्छा लग रहा है, लेकिन यह अभी भी एक श्वेत सूची है, न कि गुणों की एक ब्लैकलिस्टिंग।
मैनुअल शूवेगर्ट

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

3
मैं आपसे बहस नहीं करना चाहता। ब्लैकलिस्ट करना और श्वेतसूची बनाना एक ही परिणाम के साथ अलग-अलग दृष्टिकोण हैं, आपका दृष्टिकोण श्वेतसूची में है। जैसा कि मैंने पहले कहा था, कई तरीके हैं, लेकिन मैं विशेष रूप से एक के बारे में पूछ रहा था। इसके अलावा, आपका समाधान केवल अशक्त प्रकारों के साथ काम करता है।
मैनुअल श्वेगर्ट

1. अटैच के साथ अपने मॉडल को संलग्न करें। db.Entry (मॉडल) .Property ("namename ") के साथ गुणों के माध्यम से लूप। स्टेट = प्रॉपर्टीस्टेट। संशोधित; 3. SaveChanges करें।
एडमिर तुज़ोविक

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

8

कोई भी ईएफ़ कोर पर इसे कैसे प्राप्त करना चाहता है। यह मूल रूप से एक ही है, लेकिन अद्यतन किए जाने वाले मॉडल को जोड़ने के बाद आपका IsModified होना आवश्यक है।

db.Update(model);
db.Entry(model).Property(x => x.Token).IsModified = false;
db.SaveChanges();

पता नहीं क्यों, लेकिन मेरे ईएफ कोर में केवल स्ट्रिंग संस्करण था और मैं लैम्ब्डा का उपयोग नहीं कर सकता था। मैंने इसके बजाय नेमफ का इस्तेमाल किया लेकिन यह जाने का रास्ता है। धन्यवाद
क्यूबेलस्टर

यह उत्तर इतना "Microsofty" है मुझे पता था कि यह परीक्षण करने से पहले काम करेगा। उपरोक्त टिप्पणी के विपरीत, स्ट्रिंग और लैम्ब्डा संस्करण दोनों के परिणाम समान थे। शायद हम विभिन्न संस्करणों का उपयोग कर रहे हैं।
T3.0

3

मैंने उन संस्थाओं के गुणों को संपादित करने का एक आसान तरीका बनाया जो मैं आपके साथ साझा करूंगा। यह कोड इकाई के नाम और पारिवारिक गुणों को संपादित करेगा:

    public void EditProfileInfo(ProfileInfo profileInfo)
    {
        using (var context = new TestContext())
        {
            context.EditEntity(profileInfo, TypeOfEditEntityProperty.Take, nameof(profileInfo.Name), nameof(profileInfo.Family));
        }
    }

और यह कोड इकाई के नाम और पारिवारिक गुणों को संपादित करने के लिए अनदेखा करेगा और यह अन्य गुणों को संपादित करेगा:

    public void EditProfileInfo(ProfileInfo profileInfo)
    {
        using (var context = new TestContext())
        {
            context.EditEntity(profileInfo, TypeOfEditEntityProperty.Ignore, nameof(profileInfo.Name), nameof(profileInfo.Family));
        }
    }

इस एक्सटेंशन का उपयोग करें:

public static void EditEntity<TEntity>(this DbContext context, TEntity entity, TypeOfEditEntityProperty typeOfEditEntityProperty, params string[] properties)
   where TEntity : class
{
    var find = context.Set<TEntity>().Find(entity.GetType().GetProperty("Id").GetValue(entity, null));
    if (find == null)
        throw new Exception("id not found in database");
    if (typeOfEditEntityProperty == TypeOfEditEntityProperty.Ignore)
    {
        foreach (var item in entity.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.GetProperty))
        {
            if (!item.CanRead || !item.CanWrite)
                continue;
            if (properties.Contains(item.Name))
                continue;
            item.SetValue(find, item.GetValue(entity, null), null);
        }
    }
    else if (typeOfEditEntityProperty == TypeOfEditEntityProperty.Take)
    {
        foreach (var item in entity.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.GetProperty))
        {
            if (!item.CanRead || !item.CanWrite)
                continue;
            if (!properties.Contains(item.Name))
                continue;
            item.SetValue(find, item.GetValue(entity, null), null);
        }
    }
    else
    {
        foreach (var item in entity.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.GetProperty))
        {
            if (!item.CanRead || !item.CanWrite)
                continue;
            item.SetValue(find, item.GetValue(entity, null), null);
        }
    }
    context.SaveChanges();
}

public enum TypeOfEditEntityProperty
{
    Ignore,
    Take
}

1

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

यदि आप इसे कुछ परिदृश्यों में उपयोग करना चाहते हैं और उपरोक्त मामले में इसके "शून्यकरण" से बच सकते हैं, तो आप निम्न करने का प्रयास कर सकते हैं:

  • हिडनफॉर के साथ दृश्य में पैरामीटर छिपाएं:

    @Html.HiddenFor(m => m.Token)

यह आपके मूल मूल्य को अनमॉडिफाइड रखा जाएगा और नियंत्रक को वापस भेज दिया जाएगा।

नियंत्रक से अपनी वस्तु को फिर से लोड करें DBSetऔर इस विधि को चलाएं। आप एक श्वेत सूची और मापदंडों की एक ब्लैकलिस्ट दोनों को निर्दिष्ट कर सकते हैं जो अपडेट नहीं होगी या नहीं होगी।


आप यहाँ TryUpdateModel के बारे में अच्छी चर्चा पा सकते हैं: लिंक । जैसा कि मान्य उत्तर में कहा गया है, प्रत्येक दृश्य में आवश्यक गुणों से मेल खाने के लिए व्यूमाडेल्स बनाना बेहतर है।
Jaime

1
का उपयोग करके @Html.HiddenForदृश्य के HTML में मूल्य लिखेंगे और उपयोगकर्ता को अपने ब्राउज़र के भीतर निरीक्षण तत्व का उपयोग करने और इसे संशोधित करने की अनुमति देगा। वे ऐसा करने के बाद, यह अभी भी नियंत्रक के पास है, लेकिन एक अलग मूल्य के साथ और अद्यतन किया जाएगा। मैंने अभी इसका परीक्षण किया।
duckwizzle
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.