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


179

क्या किसी के पास "अपडेट पंक्ति को लागू करने का सबसे कारगर तरीका है, यदि उसमें कोई और प्रविष्टि है" जो कि एंटिटी फ्रेमवर्क का उपयोग करके "तर्क" है?


2
यह कुछ ऐसा है जो एक संग्रहीत कार्यविधि में डेटाबेस इंजन स्तर पर किया जाना चाहिए। अन्यथा, आपको लेनदेन में पता लगाना / अपडेट करना / सम्मिलित करना होगा।
स्टीफन चुंग

1
@ स्टेफेन: यह, वास्तव में, मैं क्या कर रहा है। धन्यवाद।
जोनाथन वुड

जोनाथन, आपका प्रश्न मेरे लिए बहुत उपयोगी है। आपने एक संग्रहीत प्रक्रिया में क्यों स्विच किया?
अनार खलीलोव

2
@ अन्नार: यह सिर्फ आसान था और मुझे बहुत अधिक कुशल होने की उम्मीद है।
जोनाथन वुड

क्या आपको हर तालिका के लिए एक संग्रहीत प्रक्रिया लिखना है?
टोफुटिम

जवाबों:


174

यदि आप संलग्न ऑब्जेक्ट (संदर्भ के एक ही उदाहरण से लोड की गई वस्तु) के साथ काम कर रहे हैं, तो आप बस उपयोग कर सकते हैं:

if (context.ObjectStateManager.GetObjectStateEntry(myEntity).State == EntityState.Detached)
{
    context.MyEntities.AddObject(myEntity);
}

// Attached object tracks modifications automatically

context.SaveChanges();

यदि आप वस्तु की कुंजी के बारे में किसी भी ज्ञान का उपयोग कर सकते हैं तो आप कुछ इस तरह से उपयोग कर सकते हैं:

if (myEntity.Id != 0)
{
    context.MyEntities.Attach(myEntity);
    context.ObjectStateManager.ChangeObjectState(myEntity, EntityState.Modified);
}
else
{
    context.MyEntities.AddObject(myEntity);
}

context.SaveChanges();

यदि आप ऑब्जेक्ट की मौजूदगी को उसकी आईडी से तय नहीं कर सकते हैं तो आपको लुकअप क्वेरी को छोड़ना होगा:

var id = myEntity.Id;
if (context.MyEntities.Any(e => e.Id == id))
{
    context.MyEntities.Attach(myEntity);
    context.ObjectStateManager.ChangeObjectState(myEntity, EntityState.Modified);
}
else
{
    context.MyEntities.AddObject(myEntity);
}

context.SaveChanges();

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

इसे देखें: stackoverflow.com/questions/3653009/… ऑब्जेक्ट संदर्भ को यथासंभव छोटा रहना चाहिए लेकिन winforms या wpf के मामले में इसका मतलब यह हो सकता है कि संदर्भ लंबे समय तक प्रस्तुतकर्ता के रूप में रह रहा है। लिंक किए गए प्रश्न में windforms में nhibernate सत्र का उपयोग करने के बारे में msdn लेख का लिंक है। एक ही दृष्टिकोण को संदर्भ के लिए इस्तेमाल किया जा सकता है।
लादिस्लाव मृका

1
लेकिन क्या होगा अगर मुझे वस्तुओं की एक सूची के साथ ऐसा करने की आवश्यकता है ... मेरे डेटाबेस में एक ही आईडी के साथ पंक्तियों की एक सूची है और मैं बदलना चाहता हूं कि क्या वे मौजूद हैं या डालें यदि वे नहीं हैं .. तो मैं इसे कैसे करूं? धन्यवाद!
फीनिक्स_यू

1
यह उत्तर LOOKS का कमाल है, लेकिन मैं इस मुद्दे पर अपडेट में चल रहा हूं: ऑब्जेक्ट के साथ एक ऑब्जेक्ट पहले से ही ObjectStateManager में मौजूद है। ObjectStateManager एक ही कुंजी के साथ कई ऑब्जेक्ट्स को ट्रैक नहीं कर सकता है।
जॉन जुमब्रम

1
ऐसा लगता है कि मैं मौजूदा वस्तु को लाने के साथ एक समस्या का एक सा हो रहा था ताकि अद्यतन करने से पहले इसकी कुंजी प्राप्त कर सके; लुकिंग ऑब्जेक्ट को अलग करने से पहले इसे ठीक करने में मदद मिली।
जॉन जुमब्रम

33

एंटिटी फ्रेमवर्क 4.3 के अनुसार, AddOrUpdateनामस्थान पर एक विधि है System.Data.Entity.Migrations:

public static void AddOrUpdate<TEntity>(
    this IDbSet<TEntity> set,
    params TEntity[] entities
)
where TEntity : class

डॉक्टर द्वारा :

SaveChanges कहे जाने पर कुंजी द्वारा संस्थाओं को जोड़ता या अद्यतन करता है। डेटाबेस शब्दावली से एक "तेज" ऑपरेशन के बराबर। माइग्रेशन का उपयोग करते हुए डेटा सीडिंग करते समय यह विधि उपयोगी हो सकती है।


@ Smashing1978 द्वारा टिप्पणी का जवाब देने के लिए , मैं @Colin द्वारा प्रदान किए गए लिंक से प्रासंगिक भागों को चिपकाऊंगा

AddOrUpdate का काम यह सुनिश्चित करना है कि जब आप विकास के दौरान डेटा बीज करते हैं तो आप डुप्लिकेट नहीं बनाते हैं।

सबसे पहले, यह आपके डेटाबेस में एक क्वेरी को निष्पादित करेगा जो एक रिकॉर्ड की तलाश में है जहाँ आपने एक कुंजी (प्रथम पैरामीटर) के रूप में आपूर्ति की है जो AddOrUpdate में आपूर्ति किए गए मैप किए गए स्तंभ मान (या मान) से मेल खाती है। तो यह मिलान के लिए थोड़ा ढीला-ढाला है, लेकिन डिजाइनिंग समय डेटा के लिए पूरी तरह से ठीक है।

इससे भी महत्वपूर्ण बात यह है कि यदि कोई मिलान पाया जाता है, तो अपडेट सभी को अपडेट करेगा और आपके AddOrUpdate में किसी भी तरह का शून्य नहीं करेगा।

उस ने कहा, मेरे पास एक ऐसी स्थिति है जहां मैं एक बाहरी सेवा से डेटा खींच रहा हूं और प्राथमिक कुंजी (और उपभोक्ताओं के लिए मेरा स्थानीय डेटा केवल-पढ़ने के लिए) द्वारा मौजूदा मूल्यों को सम्मिलित या अपडेट कर रहा है - AddOrUpdateअब और 6 महीने से अधिक समय से उत्पादन में उपयोग कर रहा है कोई समस्या नहीं है।


7
System.Data.Entity.Migrations नामस्थान में कोड-आधारित माइग्रेशन और उनके कॉन्फ़िगरेशन से संबंधित कक्षाएं होती हैं। क्या कोई कारण है कि हमें गैर-प्रवासन संस्था AddOrUpdates के लिए अपनी रिपॉजिटरी में इसका उपयोग नहीं करना चाहिए?
मैट लेंगफेल्डर

10
AddOrUpdate विधि के साथ देखभाल करें: thedatafarm.com/data-access/…
कॉलिन

1
इस लेख में बताया गया है कि AddOrUpdate का उपयोग michaelgmccarthy.com/2016/08/24/…
Nolmë Informatique

11

कॉल करते समय जादू होता है SaveChanges()और करंट पर निर्भर करता है EntityState। यदि इकाई में ए है EntityState.Added, तो इसे डेटाबेस में जोड़ा जाएगा, अगर इसमें ए है, तो इसे EntityState.Modifiedडेटाबेस में अपडेट किया जाएगा। तो आप InsertOrUpdate()निम्नानुसार एक विधि लागू कर सकते हैं:

public void InsertOrUpdate(Blog blog) 
{ 
    using (var context = new BloggingContext()) 
    { 
        context.Entry(blog).State = blog.BlogId == 0 ? 
                                   EntityState.Added : 
                                   EntityState.Modified; 

        context.SaveChanges(); 
    } 
}

EntityState के बारे में अधिक

यदि आप Id = 0यह निर्धारित करने के लिए जाँच नहीं कर सकते हैं कि यह एक नई संस्था है या नहीं, तो लद्दिस्लाव मिन्का के उत्तर की जाँच करें ।


8

यदि आप जानते हैं कि आप एक ही संदर्भ का उपयोग कर रहे हैं और किसी भी संस्था को अलग नहीं कर रहे हैं, तो आप इस तरह से एक सामान्य संस्करण बना सकते हैं:

public void InsertOrUpdate<T>(T entity, DbContext db) where T : class
{
    if (db.Entry(entity).State == EntityState.Detached)
        db.Set<T>().Add(entity);

    // If an immediate save is needed, can be slow though
    // if iterating through many entities:
    db.SaveChanges(); 
}

db निश्चित रूप से एक वर्ग क्षेत्र हो सकता है, या विधि को स्थिर और एक विस्तार बनाया जा सकता है, लेकिन यह मूल बातें है।


4

लादिस्लाव का जवाब करीब था लेकिन मुझे EF6 (डेटाबेस-प्रथम) में काम करने के लिए कुछ संशोधन करने पड़े। मैंने AddOrUpdate पद्धति पर अपना डेटा संदर्भ बढ़ाया और अब तक यह अलग वस्तुओं के साथ अच्छी तरह से काम करता प्रतीत होता है:

using System.Data.Entity;

[....]

public partial class MyDBEntities {

  public void AddOrUpdate(MyDBEntities ctx, DbSet set, Object obj, long ID) {
      if (ID != 0) {
          set.Attach(obj);
          ctx.Entry(obj).State = EntityState.Modified;
      }
      else {
          set.Add(obj);
      }
  }
[....]

AddOrUpdate भी System.Data.Entity.Migrations में एक विस्तार विधि के रूप में मौजूद है, इसलिए अगर मैं तुम मैं अपने तरीके के लिए एक ही विधि का नाम पुन: उपयोग करने से बचना होगा।
15:24 पर

2

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

यह स्वचालित रूप से Addedया के लिए संस्थाओं की स्थिति निर्धारित करेगा Modified। और आप मैन्युअल रूप से चुनेंगे कि किन संस्थाओं को हटा दिया जाना चाहिए अगर यह मौजूद नहीं है।

उदाहरण:

मान लीजिए कि मुझे एक Personवस्तु मिली है । Personकई फोन, एक दस्तावेज़ और एक पति या पत्नी हो सकता है।

public class Person
{
     public int Id { get; set; }
     public string FirstName { get; set; }
     public string LastName { get; set; }
     public string MiddleName { get; set; }
     public int Age { get; set; }
     public int DocumentId {get; set;}

     public virtual ICollection<Phone> Phones { get; set; }
     public virtual Document Document { get; set; }
     public virtual PersonSpouse PersonSpouse { get; set; }
}

मैं उन सभी संस्थाओं की स्थिति को निर्धारित करना चाहता हूं जो ग्राफ में शामिल हैं।

context.InsertOrUpdateGraph(person)
       .After(entity =>
       {
            // Delete missing phones.
            entity.HasCollection(p => p.Phones)
               .DeleteMissingEntities();

            // Delete if spouse is not exist anymore.
            entity.HasNavigationalProperty(m => m.PersonSpouse)
                  .DeleteIfNull();
       });

जैसा कि आप जानते हैं कि अद्वितीय महत्वपूर्ण गुण फ़ोन इकाई की स्थिति को परिभाषित करते समय भूमिका निभा सकते हैं। ऐसे विशेष उद्देश्यों के लिए हमारे पास ExtendedEntityTypeConfiguration<>वर्ग है, जो विरासत में मिला है EntityTypeConfiguration<>। अगर हम इस तरह के विशेष विन्यासों का उपयोग करना चाहते हैं तो हमें अपनी मैपिंग कक्षाओं से विरासत में लेनी चाहिए ExtendedEntityTypeConfiguration<>, बजाय EntityTypeConfiguration<>। उदाहरण के लिए:

public class PhoneMap: ExtendedEntityTypeConfiguration<Phone>
    {
        public PhoneMap()
        {
             // Primary Key
             this.HasKey(m => m.Id);
              
             // Unique keys
             this.HasUniqueKey(m => new { m.Prefix, m.Digits });
        }
    }

बस इतना ही।


2

दोनों को और अपडेट डालें

public void InsertUpdateData()
{
//Here TestEntities is the class which is given from "Save entity connection setting in web.config"
TestEntities context = new TestEntities();

var query = from data in context.Employee
            orderby data.name
            select data;

foreach (Employee details in query)
{
    if (details.id == 1)
    {
        //Assign the new values to name whose id is 1
        details.name = "Sanjay";
        details. Surname="Desai";
        details.address=" Desiwadi";
    }
    else if(query==null)
    {
        details.name="Sharad";
        details.surname=" Chougale ";
        details.address=" Gargoti";
    }
}

//Save the changes back to database.
context.SaveChanges();
}

मैंने इस दृष्टिकोण का उपयोग किया लेकिन (पहले या डिफ़ॉल्ट के बाद) जाँच की अगर (क्वेरी == अशक्त)
पैट्रिक

2

किसी के साथ मौजूदा पंक्ति की जाँच करें।

    public static void insertOrUpdateCustomer(Customer customer)
    {
        using (var db = getDb())
        {

            db.Entry(customer).State = !db.Customer.Any(f => f.CustomerId == customer.CustomerId) ? EntityState.Added : EntityState.Modified;
            db.SaveChanges();

        }

    }

1

वैकल्पिक के लिए @LadislavMrnka उत्तर। अगर यह एंटिटी फ्रेमवर्क 6.2.0 के लिए है।

यदि आपके पास एक विशिष्ट DbSetऔर एक आइटम है जिसे या तो अद्यतन या निर्मित करने की आवश्यकता है:

var name = getNameFromService();

var current = _dbContext.Names.Find(name.BusinessSystemId, name.NameNo);
if (current == null)
{
    _dbContext.Names.Add(name);
}
else
{
    _dbContext.Entry(current).CurrentValues.SetValues(name);
}
_dbContext.SaveChanges();

हालाँकि यह DbSetएकल प्राथमिक कुंजी या समग्र प्राथमिक कुंजी के साथ सामान्य के लिए भी उपयोग किया जा सकता है ।

var allNames = NameApiService.GetAllNames();
GenericAddOrUpdate(allNames, "BusinessSystemId", "NameNo");

public virtual void GenericAddOrUpdate<T>(IEnumerable<T> values, params string[] keyValues) where T : class
{
    foreach (var value in values)
    {
        try
        {
            var keyList = new List<object>();

            //Get key values from T entity based on keyValues property
            foreach (var keyValue in keyValues)
            {
                var propertyInfo = value.GetType().GetProperty(keyValue);
                var propertyValue = propertyInfo.GetValue(value);
                keyList.Add(propertyValue);
            }

            GenericAddOrUpdateDbSet(keyList, value);
            //Only use this when debugging to catch save exceptions
            //_dbContext.SaveChanges();
        }
        catch
        {
            throw;
        }
    }
    _dbContext.SaveChanges();
}

public virtual void GenericAddOrUpdateDbSet<T>(List<object> keyList, T value) where T : class
{
    //Get a DbSet of T type
    var someDbSet = Set(typeof(T));

    //Check if any value exists with the key values
    var current = someDbSet.Find(keyList.ToArray());
    if (current == null)
    {
        someDbSet.Add(value);
    }
    else
    {
        Entry(current).CurrentValues.SetValues(value);
    }
}

-1

संशोधित

public static void InsertOrUpdateRange<T, T2>(this T entity, List<T2> updateEntity) 
        where T : class
        where T2 : class
        {
            foreach(var e in updateEntity)
            {
                context.Set<T2>().InsertOrUpdate(e);
            }
        }


        public static void InsertOrUpdate<T, T2>(this T entity, T2 updateEntity) 
        where T : class
        where T2 : class
        {
            if (context.Entry(updateEntity).State == EntityState.Detached)
            {
                if (context.Set<T2>().Any(t => t == updateEntity))
                {
                   context.Set<T2>().Update(updateEntity); 
                }
                else
                {
                    context.Set<T2>().Add(updateEntity);
                }

            }
            context.SaveChanges();
        }

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