সত্তা কাঠামো সত্তা পরিবর্তনগুলি পূর্বাবস্থায় ফেরান


116

এটি একটি তুচ্ছ প্রশ্ন হতে পারে তবে: যেহেতু ADO.NET সত্তা কাঠামোটি স্বয়ংক্রিয়ভাবে পরিবর্তনগুলি (উত্পাদিত সত্তাগুলিতে) ট্র্যাক করে এবং তাই মূল মানগুলি রাখে, সত্তা অবজেক্টগুলিতে করা পরিবর্তনগুলি আমি কীভাবে রোলব্যাক করব?

আমার একটি ফর্ম রয়েছে যা ব্যবহারকারীকে গ্রিড ভিউতে "গ্রাহক" সত্তার একটি সেট সম্পাদনা করতে দেয়।

এখন আমার দুটি বোতাম "গ্রহণ" এবং "রিভার্ট" রয়েছে: "স্বীকার করুন" ক্লিক করা হলে, আমি কল করি Context.SaveChanges()এবং পরিবর্তিত অবজেক্টগুলি ডাটাবেসে ফিরে লেখা হয়। যদি "রিভার্ট" ক্লিক করা থাকে তবে আমি চাইব যে সমস্ত বস্তু তাদের মূল সম্পত্তির মান পাবে। তার জন্য কোডটি কী হবে?

ধন্যবাদ

উত্তর:


69

ইএফ-তে কোনও পরিবর্তন বা বাতিল বিকল্প নেই। প্রতিটি সত্তা রয়েছে ObjectStateEntryObjectStateManager। রাজ্যের এন্ট্রিতে আসল ও আসল মান থাকে তাই আপনি বর্তমান মানগুলি ওভাররাইট করতে মূল মানগুলি ব্যবহার করতে পারেন তবে প্রতিটি সত্তার জন্য আপনাকে এটি ম্যানুয়ালি করতে হবে। এটি নেভিগেশন বৈশিষ্ট্য / সম্পর্কের পরিবর্তনকে প্রশংসিত করবে না।

"পরিবর্তনগুলি প্রত্যাবর্তন" করার সাধারণ উপায় হ'ল প্রসঙ্গটি নিষ্পত্তি করা এবং সত্তাগুলি পুনরায় লোড করা। আপনি যদি পুনরায় লোড এড়াতে চান তবে আপনাকে অবশ্যই সত্ত্বার ক্লোন তৈরি করতে হবে এবং নতুন অবজেক্ট প্রসঙ্গে সেই ক্লোনগুলি সংশোধন করতে হবে। যদি ব্যবহারকারী পরিবর্তনগুলি বাতিল করে তবে আপনার কাছে এখনও মূল সত্ত্বা থাকবে।


4
@ লাডিস্লাভ মির্নকা নিশ্চয়ই Context.Refresh()আপনার দাবির প্রতি-উদাহরণ যে কোনও রিভার্ট অপারেশন নেই? ব্যবহার Refresh()আরো ভালো পদ্ধতির (যেমন আরও সহজে নির্দিষ্ট সত্ত্বা লক্ষ্য) প্রসঙ্গ ত্যাগী এবং সমস্ত ট্র্যাক করা পরিবর্তনগুলির হারিয়ে যাওয়া চেয়ে মনে।
রব

14
@robjb: নং রিফ্রেশ কেবলমাত্র একক সত্তা বা সত্তা সংস্থাগুলির সংগ্রহকে রিফ্রেশ করতে সক্ষম যা আপনি ম্যানুয়ালি সংজ্ঞায়িত করেছেন তবে রিফ্রেশ কার্যকারিতা কেবল সাধারণ বৈশিষ্ট্যগুলিকে (সম্পর্ক নয়) প্রভাবিত করে। এটি যুক্ত বা মুছে ফেলা সত্তাগুলির সমস্যাও সমাধান করে না।
লাদিস্লাভ মৃঙ্কা

153

নোংরা আইটেমগুলির জন্য DbContext এর ক্যুরিয়ার চেঞ্জট্র্যাকার। অপরিবর্তিত ও মুছে ফেলা আইটেমগুলি বিচ্ছিন্ন করতে মুছে ফেলা আইটেমগুলির স্থিতি সেট করুন। পরিবর্তিত আইটেমগুলির জন্য, মূল মানগুলি ব্যবহার করুন এবং প্রবেশের বর্তমান মানগুলি সেট করুন। অবশেষে পরিবর্তিত এন্ট্রি এর স্থিতি সেট করুন:

public void RollBack()
{
    var context = DataContextFactory.GetDataContext();
    var changedEntries = context.ChangeTracker.Entries()
        .Where(x => x.State != EntityState.Unchanged).ToList();

    foreach (var entry in changedEntries)
    {
        switch(entry.State)
        {
            case EntityState.Modified:
                entry.CurrentValues.SetValues(entry.OriginalValues);
                entry.State = EntityState.Unchanged;
                break;
            case EntityState.Added:
                entry.State = EntityState.Detached;
                break;
            case EntityState.Deleted:
                entry.State = EntityState.Unchanged;
                break;
        }
    }
 }

3
ধন্যবাদ - এটি সত্যিই আমাকে সাহায্য করেছে!
ম্যাট

5
আপনার সম্ভবত মুছে যাওয়া এন্ট্রিগুলিতেও মূল মানগুলি সেট করা উচিত। আপনি প্রথমে কোনও আইটেম পরিবর্তন করে তার পরে মুছে ফেলা সম্ভব।
বাস ডি রাদ

22
সেট Stateথেকে EntityState.Unchanged সঙ্গে সব মান অগ্রাহ্য করবে Original Valuesপাশাপাশি তাই কলে কোন প্রয়োজন নেই SetValuesপদ্ধতি।
আবলফাজল হোসনোদ্দিন

10
এই উত্তরটি এর ক্লিনার সংস্করণ: stackoverflow.com/a/22098063/2498426
Jerther

1
সাথ, এই দুর্দান্ত! কেবলমাত্র আমি সম্পাদনা করেছি এন্ট্রি <টি> () এর জেনেরিক সংস্করণটি ব্যবহার করা যাতে এটি আমার শরণার্থীদের জন্য কাজ করে। এটি আমাকে আরও নিয়ন্ত্রণ দেয় এবং সত্তা টাইপের জন্য আমি ফিরে যেতে পারি। ধন্যবাদ!
ড্যানিয়েল

33
dbContext.Entry(entity).Reload();

এমএসডিএন- তে অভিযুক্ত :

ডাটাবেস থেকে মানগুলির সাথে কোনও সম্পত্তি মান ওভাররাইট করে ডাটাবেস থেকে সত্তাটি পুনরায় লোড করে। এই পদ্ধতিটি কল করার পরে সত্তাটি অপরিবর্তিত অবস্থায় থাকবে।

নোট করুন যে ডাটাবেসে অনুরোধটি ফিরিয়ে আনার কিছু ত্রুটি রয়েছে:

  • নেটওয়ার্ক ট্রাফিক
  • ডিবি ওভারলোড
  • বর্ধিত অ্যাপ্লিকেশন প্রতিক্রিয়া সময়

17

এটি আমার পক্ষে কাজ করেছে:

dataContext.customer.Context.Refresh(RefreshMode.StoreWins, item);

itemগ্রাহক সত্তা কোথায় ফেরানো হবে।


12

কোনও পরিবর্তন ট্র্যাক না করে সহজ উপায়। এটি প্রতিটি সত্তার চেয়ে তত দ্রুত হওয়া উচিত।

public void Rollback()
{
    dataContext.Dispose();
    dataContext= new MyEntities(yourConnection);
}

একটি একক এনটাইটিলিটি অবজেক্ট তৈরির সময় ... যা কয়েক মিল (এমএস)। সংগ্রহের মাধ্যমে লুপিং এটির আকারের উপর নির্ভর করে একটি দ্রুত বা দীর্ঘতর হতে পারে। পারফরম্যান্স ওয়াই ও (1) ও (এন) এর সাথে তুলনা করে খুব কমই সমস্যা। বিগ হে স্বরলিপি
Guish

আপনাকে অনুসরণ করছে না - সংযোগ পুনরুদ্ধার এবং পুনরুদ্ধারের কর্মক্ষমতা। আমি এটি বিদ্যমান প্রকল্পে পরীক্ষা করেছি এবং এটি Rollbackপ্রক্রিয়াটির উপরে কিছুটা দ্রুত শেষ হয়েছে , যদি কেউ পুরো ডাটাবেসের স্থিতি ফিরে পেতে চায় তবে এটি আরও ভাল পছন্দ করে তোলে। রোলব্যাক চেরি বেছে নিতে পারে।
majkinetor

'এন' অর্থ বস্তুর সংখ্যা। পুনরায় সংযোগ স্থাপন করতে প্রায় 50 এমএস সময় লাগে ... ও (1) এর অর্থ এটি সর্বদা একই সময় 50ms+0*n= 50ms। ও (এন) এর অর্থ পারফরম্যান্স বস্তুর সংখ্যার দ্বারা প্রভাবিত হয় ... পারফরম্যান্স হতে পারে 2ms+0.5ms*n... সুতরাং 96 টি নমুনা দ্রুততর হবে তবে ডেটার পরিমাণের সাথে সময় রৈখিকভাবে বৃদ্ধি পাবে।
Guish

আপনি যদি চেরি না যাচ্ছেন তবে কী পাকানো হবে তা বাছাই করা হবে না তবে আপনি যদি ব্যান্ডউইথ সম্পর্কে উদ্বিগ্ন হন না তবে এটি উপায়।
অ্যান্টনি নিকোলস

6
// Undo the changes of all entries. 
foreach (DbEntityEntry entry in context.ChangeTracker.Entries()) 
{ 
    switch (entry.State) 
    { 
        // Under the covers, changing the state of an entity from  
        // Modified to Unchanged first sets the values of all  
        // properties to the original values that were read from  
        // the database when it was queried, and then marks the  
        // entity as Unchanged. This will also reject changes to  
        // FK relationships since the original value of the FK  
        // will be restored. 
        case EntityState.Modified: 
            entry.State = EntityState.Unchanged; 
            break; 
        case EntityState.Added: 
            entry.State = EntityState.Detached; 
            break; 
        // If the EntityState is the Deleted, reload the date from the database.   
        case EntityState.Deleted: 
            entry.Reload(); 
            break; 
        default: break; 
    } 
} 

এটা আমার জন্য কাজ করেছে। তবে আপনাকে পুরানো ডেটা আনতে প্রসঙ্গ থেকে আপনার ডেটা পুনরায় লোড করতে হবে। উত্স এখানে


3

"এটি আমার পক্ষে কাজ করেছে:

dataContext.customer.Context.Refresh(RefreshMode.StoreWins, item);

itemগ্রাহক সত্তাটি কোথায় ফেরানো হবে।


আমি এসকিউএল অ্যাজুরিতে অবজেক্ট কনটেক্সট.-রিফ্রেশ দিয়ে পরীক্ষা করেছি এবং "রিফ্রেশমোড.স্টোর উইনস" প্রতিটি সত্তার জন্য ডাটাবেসের বিরুদ্ধে একটি জিজ্ঞাসা ফায়ার করে একটি পারফরম্যান্স ফাঁসের কারণ ঘটায়। মাইক্রোসফ্ট ডকুমেন্টেশন () এর উপর ভিত্তি করে:

ক্লায়েন্টওইনস: অবজেক্ট প্রসঙ্গে আইটেমগুলিতে করা সম্পত্তি পরিবর্তনগুলি ডেটা উত্স থেকে মানগুলির সাথে প্রতিস্থাপন করা হয় না। সেভচেনজেস-এর পরবর্তী কলে, এই পরিবর্তনগুলি ডেটা উত্সে প্রেরণ করা হয়।

স্টোরউইনস: অবজেক্ট প্রসঙ্গে আইটেমগুলিতে করা সম্পত্তি পরিবর্তনগুলি ডেটা উত্স থেকে মানগুলির সাথে প্রতিস্থাপিত হয়।

ক্লায়েন্ট উইনসও ভাল ধারণা নয়, কারণ গুলি চালানো ave সেভচেনেজগুলি ডেটাসোর্সটিতে "বাতিল" পরিবর্তনগুলি প্রতিশ্রুতিবদ্ধ।

আমি এখনও জানি না যে সর্বোত্তম উপায়টি কী, কারণ প্রসঙ্গটি নিষ্পত্তি করা এবং একটি নতুন তৈরি করা বার্তার সাথে ব্যতিক্রম ঘটায়: "অন্তর্নিহিত সরবরাহকারী খোলা ব্যর্থ হয়েছিল" যখন আমি তৈরি হওয়া নতুন প্রসঙ্গে কোনও জিজ্ঞাসা চালানোর চেষ্টা করি।

শুভেচ্ছান্তে,

হেনরিক ক্লাউজিং


2

আমার হিসাবে, এটি করার আরও ভাল পদ্ধতিটি হ'ল EntityState.Unchangedআপনি যে পরিবর্তনগুলি পূর্বাবস্থায় ফিরতে চান তার প্রতিটি সত্তাকে সেট করা। এটি আশ্বাস দেয় যে পরিবর্তনগুলি এফকে-তে ফিরিয়ে দেওয়া হয়েছে এবং এতে আরও কিছুটা পরিষ্কার বাক্য গঠন রয়েছে।


4
দ্রষ্টব্য: সত্তাটি আবার পরিবর্তন করা হলে পরিবর্তনগুলি ফিরে আসবে।
নিক তিমি

2

আমি এটি আমার প্রসঙ্গে ভাল কাজ করে দেখলাম:

Context.ObjectStateManager.ChangeObjectState(customer, EntityState.Unchanged);


1
আমি বিশ্বাস করি DbContext.SaveChanges()এটি কল করার পরে অস্তিত্বের পরিবর্তনগুলি রোধ করবে , তবে এটি সত্তার মানগুলি মূল মানগুলিতে ফিরিয়ে দেবে না। এবং যদি সত্তা রাজ্যটি পরবর্তী কোনও পরিবর্তন থেকে সংশোধিত হয়ে যায়, সম্ভবত সমস্ত পূর্ববর্তী পরিবর্তনগুলি সংরক্ষণের পরে অবিরত থাকবে?
কার্ল জি

1
এই লিঙ্ক কোডটি চেক করুন.এসএসডিএন.মাইক্রোসফটকম / হাও- টু-undo-the-changes-in-00aed3c4 এটি বলছে যে অপরিবর্তিত অবস্থায় একটি সত্তা নির্ধারণ করা "কভারের নীচে" মূল মানগুলিকে পুনরুদ্ধার করে।
হ্যানিশ

2

এটি মৃঙ্কা কী নিয়ে কথা বলছেন তার একটি উদাহরণ। নিম্নলিখিত পদ্ধতিটি মূল সত্ত্বার সাথে সত্তার বর্তমান মানগুলিকে ওভাররাইট করে এবং ডেটাবেস কল করে না । আমরা এটি DbEntityEntry এর অরিজিনালভ্যালু সম্পত্তি ব্যবহার করে এবং মানকে সাধারণ পদ্ধতিতে সেট করার জন্য প্রতিবিম্বটি ব্যবহার করি। (এটি সত্ত্বা ফ্রেমওয়ার্ক 5.0 হিসাবে কাজ করে)

/// <summary>
/// Undoes any pending updates 
/// </summary>
public void UndoUpdates( DbContext dbContext )
{
    //Get list of entities that are marked as modified
    List<DbEntityEntry> modifiedEntityList = 
        dbContext.ChangeTracker.Entries().Where(x => x.State == EntityState.Modified).ToList();

    foreach(  DbEntityEntry entity in modifiedEntityList ) 
    {
        DbPropertyValues propertyValues = entity.OriginalValues;
        foreach (String propertyName in propertyValues.PropertyNames)
        {                    
            //Replace current values with original values
            PropertyInfo property = entity.Entity.GetType().GetProperty(propertyName);
            property.SetValue(entity.Entity, propertyValues[propertyName]); 
        }
    }
}

1

লিগ্যাসি অবজেক্ট প্রসঙ্গে আমরা ইএফ 4 ব্যবহার করছি। উপরের সমাধানগুলির মধ্যে কোনটিই সরাসরি আমার জন্য উত্তর দেয়নি - যদিও এটি দীর্ঘ সময় ধরে আমাকে সঠিক দিকে ঠেলে দিয়ে এর উত্তর দেয়।

আমরা কেবলমাত্র প্রসঙ্গটি নিষ্পত্তি করতে এবং পুনর্নির্মাণ করতে পারি না কারণ আমরা স্মৃতিতে ঘুরতে থাকা কয়েকটি অবজেক্ট (অভিশাপ যে অলস বোঝা !!) এখনও প্রসঙ্গের সাথে সংযুক্ত রয়েছে তবে এমন বাচ্চা রয়েছে যেগুলি এখনও ভারী বোঝায় না। এই ক্ষেত্রেগুলির জন্য আমাদের ডাটাবেসকে হাতুড়ি না দিয়ে এবং বিদ্যমান সংযোগটি বাদ দিয়ে মূল মানগুলিতে ফিরে আসা উচিত b

নীচে এই একই সমস্যার সমাধান:

    public static void UndoAllChanges(OurEntities ctx)
    {
        foreach (ObjectStateEntry entry in
            ctx.ObjectStateManager.GetObjectStateEntries(~EntityState.Detached))
        {
            if (entry.State != EntityState.Unchanged)
            {
                ctx.Refresh(RefreshMode.StoreWins, entry.Entity);
            }
        }
    }

আমি এই অন্যদের সাহায্য করে আশা করি।


0

উপরের কয়েকটি ভাল ধারণা, আমি আইসিলোনেবল এবং তারপরে একটি সাধারণ এক্সটেনশন পদ্ধতি বাস্তবায়ন করতে বেছে নিয়েছি।

এখানে পাওয়া গেছে: আমি সি # তে জেনেরিক তালিকাটি কীভাবে ক্লোন করব?

হিসাবে ব্যবহার করা হবে:

ReceiptHandler.ApplyDiscountToAllItemsOnReciept(LocalProductsOnReciept.Clone(), selectedDisc);

এইভাবে আমি আমার পণ্য সত্তাগুলির তালিকা ক্লোন করতে সক্ষম হয়েছি, প্রতিটি আইটেমের জন্য ছাড় প্রয়োগ করেছি এবং আসল সত্তায় কোনও পরিবর্তন ফিরিয়ে আনতে চিন্তার দরকার নেই। ডিবিসিঙ্কটেক্সটের সাথে কথা বলার এবং একটি রিফ্রেশ চাইতে বা চেঞ্জট্র্যাকার দিয়ে কাজ করার দরকার নেই। আপনি বলতে পারেন যে আমি EF6 এর সম্পূর্ণ ব্যবহার করছি না তবে এটি একটি খুব সুন্দর এবং সাধারণ বাস্তবায়ন এবং একটি ডিবি হিট এড়িয়ে চলে। এর পারফরম্যান্স হিট আছে কি না তা আমি বলতে পারি না।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.