আমি কি কোনও সংযুক্ত অথচ সমান বস্তু ব্যবহার করে কোনও সংযুক্ত বস্তু আপডেট করতে পারি?


10

আমি একটি বাহ্যিক এপিআই থেকে মুভি ডেটা পুনরুদ্ধার করি। প্রথম পর্যায়ে আমি প্রতিটি মুভি স্ক্র্যাপ করব এবং এটিকে আমার নিজের ডাটাবেসে প্রবেশ করিয়ে দেব। দ্বিতীয় ধাপে আমি পর্যায়ক্রমে এপিআইয়ের "পরিবর্তনগুলি" এপিআই ব্যবহার করে আমার ডেটাবেস আপডেট করব যা কোন চলচ্চিত্রের তথ্য পরিবর্তন হয়েছিল তা দেখার জন্য আমি জিজ্ঞাসা করতে পারি।

আমার ORM স্তরটি হ'ল সত্ত্বা-ফ্রেমওয়ার্ক। মুভি ক্লাসটি দেখতে এমন দেখাচ্ছে:

class Movie
{
    public virtual ICollection<Language> SpokenLanguages { get; set; }
    public virtual ICollection<Genre> Genres { get; set; }
    public virtual ICollection<Keyword> Keywords { get; set; }
}

সমস্যা দেখা দেয় দুটো কারণে যখন আমি একটি চলচ্চিত্র আপডেট করা প্রয়োজন আছে: আমার ডাটাবেসের বস্তুর মনে হবে ট্র্যাক করা হচ্ছে এবং নতুন এক আমি বিভিন্ন বস্তু হিসেবে আপডেট এপিআই কল, disregarding কাছ থেকে যে .Equals()

এটি একটি সমস্যার কারণ কারণ যখন আমি এখন আপডেট মুভিটি দিয়ে ডেটাবেস আপডেট করার চেষ্টা করব তখন এটি বিদ্যমান মুভিটি আপডেট করার পরিবর্তে এটি সন্নিবেশ করবে।

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

এটি একটি বরং দুর্গন্ধযুক্ত পদ্ধতির কারণ যদি আমি আমার Movieঅবজেক্টে এই পদ্ধতির ধারা অব্যাহত রাখি তবে এর অর্থ হ'ল আমাকে চলচ্চিত্র, ভাষা, ঘরানা এবং কীওয়ার্ডগুলি পৃথক করে রাখতে হবে, ডাটাবেসে প্রত্যেককে অনুসন্ধান করতে হবে, তাদের আইডি স্থানান্তর করতে হবে এবং সন্নিবেশ করানো হবে নতুন বস্তু

আরও কি মার্জিতভাবে এটি করার উপায় আছে? আদর্শভাবে আমি কেবল প্রসঙ্গে প্রযোজ্য মুভিটিতে যেতে চাই এবং Equals()পদ্ধতির উপর ভিত্তি করে আপডেট করতে , তার সমস্ত ক্ষেত্র আপডেট করতে এবং প্রতিটি জটিল অবজেক্টের জন্য সঠিক মুভিটি নির্বাচন করতে চাই : তার নিজস্ব Equals()পদ্ধতির ভিত্তিতে আবার বিদ্যমান রেকর্ডটি ব্যবহার করুন এবং যদি সন্নিবেশ করান তবে এটি এখনও নেই।

আমি .Update()প্রতিটি জটিল বস্তুর উপর পদ্ধতি সরবরাহ করে বিচ্ছিন্নকরণ / সংযুক্তি এড়িয়ে যেতে পারি যা আমি সমস্ত সংযুক্ত বস্তু পুনরুদ্ধারের সংমিশ্রণে ব্যবহার করতে পারি তবে এটি আপডেট করার জন্য আমার এখনও বিদ্যমান প্রতিটি অবজেক্টটি পুনরুদ্ধার করতে হবে।


আপনি কেন কেবল আপনার এপিআই ডেটা থেকে ট্র্যাক করা সত্তাকে আপডেট করতে এবং সত্ত্বাকে প্রতিস্থাপন / ডিচাচিং / ম্যাচিং / সংযুক্তি ব্যতীত পরিবর্তনগুলি সংরক্ষণ করতে পারবেন না?
সি-এন

@ সি-এন: আপনি কীভাবে প্রসারিত করতে পারবেন ঠিক তখন কীভাবে চলবে?
জেরোইন ভেনেভেল

ঠিক আছে এখন আপনি যুক্ত করেছেন যে শেষ অনুচ্ছেদে এটি আরও অর্থবোধক হয়েছে, সত্তাগুলি আপডেট করার আগে আপনি সেগুলি পুনরুদ্ধার এড়াতে চেষ্টা করছেন? আপনার মুভি ক্লাসে আপনার পিকে হতে পারে এমন কিছুই নেই? আপনি কীভাবে বাহ্যিক এপি থেকে আপনার সত্তাগুলির সাথে চলচ্চিত্রের মিল করছেন? আপনি যে কোনও উপায়ে একটি ডিবি কলে আপডেট করতে হবে এমন সমস্ত সত্ত্বা আপনি পুনরুদ্ধার করতে পারেন, এটি কি এমন সহজ সমাধান নয় যা কোনও বড় পারফরম্যান্সের হিট না ঘটায় (যদি না আপনি আপডেট করার জন্য বিশাল সংখ্যক চলচ্চিত্রের কথা না বলছেন)?
সি-এন

আমার মুভি ক্লাসটির একটি পিকে রয়েছে idএবং বাহ্যিক এপিআইয়ের চলচ্চিত্রগুলি ফিল্ডটি ব্যবহার করে স্থানীয়দের সাথে মেলে tmdbid। মুভি, ঘরানা, ভাষা, কীওয়ার্ড ইত্যাদির সম্পর্কে একটি কালে আপডেট হওয়া দরকার এমন সমস্ত সত্তা আমি পুনরুদ্ধার করতে পারছি না এইগুলির প্রত্যেকটিরই পিকে রয়েছে এবং এটি ডেটাবেসে ইতিমধ্যে বিদ্যমান থাকতে পারে।
জেরোইন ভেনেভেল

উত্তর:


8

আমি যা প্রত্যাশা করছিলাম তা খুঁজে পেলাম না তবে বিদ্যমান নির্বাচন-বিচ্ছিন্নতা-আপডেট-সংযুক্তি ক্রমের তুলনায় আমি একটি উন্নতি পেয়েছি।

এক্সটেনশন পদ্ধতি AddOrUpdate(this DbSet)আপনাকে আমি যা করতে চাই ঠিক তা করতে দেয়: এটি সেখানে না থাকলে sertোকান এবং এটি যদি বিদ্যমান মান খুঁজে পায় তবে আপডেট করুন। আমি এটিকে শীঘ্রই ব্যবহার করার বিষয়টি বুঝতে পারি নি যেহেতু আমি সত্যিই কেবল seed()মাইগ্রেশনগুলির সাথে মিশ্রিত পদ্ধতিতে এটি ব্যবহার করতে দেখেছি । আমার যদি এটি ব্যবহার না করার কোনও কারণ থাকে তবে আমাকে জানান।

লক্ষণীয় দরকারী কিছু: একটি ওভারলোড উপলব্ধ রয়েছে যা আপনাকে নির্দিষ্ট করে সাম্য কীভাবে নির্ধারণ করা উচিত তা নির্বাচন করতে দেয়। এখানে আমি আমার ব্যবহার করতে পারতাম TMDbIdতবে আমি পরিবর্তে কেবল নিজের আইডিটিকে পুরোপুরি উপেক্ষা করতে এবং পরিবর্তে টিএমডিবিআইডিতে একটি পিকে ব্যবহারের বিকল্পটি বেছে নিয়েছি DatabaseGeneratedOption.None। আমি যথাযথ যেখানে প্রতিটি উপ-সংগ্রহের উপরও এই পদ্ধতির ব্যবহার করি।

উত্স আকর্ষণীয় অংশ :

internalSet.InternalContext.Owner.Entry(existing).CurrentValues.SetValues(entity);

যা হুডের নীচে ডেটা আসলে আপডেট হয়।

যা কিছু বাকী রয়েছে সেগুলিই AddOrUpdateপ্রতিটি বস্তুকে ডাকে যে আমি এটি দ্বারা প্রভাবিত হতে চাই:

public void InsertOrUpdate(Movie movie)
{
    _context.Movies.AddOrUpdate(movie);
    _context.Languages.AddOrUpdate(movie.SpokenLanguages.ToArray());
    // Other objects/collections
    _context.SaveChanges();
}

আমি যতটা আশা করেছিলাম ততটা পরিষ্কার নয় যেহেতু আমার নিজের আইটেমের প্রতিটি টুকরোগুলি ম্যানুয়ালি উল্লেখ করতে হবে যা আপডেট করা দরকার তবে এটি যতটা কাছে আসবে তত কাছাকাছি।

সম্পর্কিত পঠন: /programming/15336248/entity-framework-5-updating-a-record


হালনাগাদ:

দেখা যাচ্ছে আমার পরীক্ষাগুলি যথেষ্ট কঠোর ছিল না। এই কৌশলটি ব্যবহার করার পরে আমি লক্ষ্য করেছি যে নতুন ভাষা যুক্ত হওয়ার সময় এটি মুভিটির সাথে সংযুক্ত ছিল না। বহু থেকে বহু টেবিলের মধ্যে। এটি একটি জ্ঞাত তবে আপাতদৃষ্টিতে নিম্ন-অগ্রাধিকারযুক্ত সমস্যা এবং যতদূর আমি জানি ঠিক করা হয়নি।

শেষ পর্যন্ত আমি সিদ্ধান্ত নিয়েছি যেখানে আমার Update(T)প্রতিটি ধরণের পদ্ধতি রয়েছে এবং এই ইভেন্টগুলির ক্রমটি অনুসরণ করব:

  • নতুন অবজেক্টে সংগ্রহের উপর লুপ করুন
  • প্রতিটি সংগ্রহে প্রতিটি প্রবেশের জন্য এটি ডাটাবেসে সন্ধান করুন
  • যদি এটি বিদ্যমান থাকে Update()তবে নতুন মান সহ এটি আপডেট করার জন্য পদ্ধতিটি ব্যবহার করুন
  • যদি এটি বিদ্যমান না থাকে তবে উপযুক্ত ডিবিসেটে এটি যুক্ত করুন
  • সংযুক্ত বস্তুগুলি ফিরিয়ে নিন এবং সংযুক্ত বস্তুর সংগ্রহের সাহায্যে মূল অবজেক্টে সংগ্রহগুলি প্রতিস্থাপন করুন
  • রুট অবজেক্টটি সন্ধান করুন এবং আপডেট করুন

এটি অনেকগুলি ম্যানুয়াল কাজ এবং এটি কুৎসিত তাই এটি আরও কয়েকটি সংশোধনকারীদের মধ্য দিয়ে যাবে তবে এখন আমার পরীক্ষাগুলি ইঙ্গিত করে যে এটি আরও কঠোর পরিস্থিতিতে কাজ করা উচিত।


আরও পরিষ্কার করার পরে আমি এখন এই পদ্ধতিটি ব্যবহার করছি:

private IEnumerable<T> InsertOrUpdate<T, TKey>(IEnumerable<T> entities, Func<T, TKey> idExpression) where T : class
{
    foreach (var entity in entities)
    {
        var existingEntity = _context.Set<T>().Find(idExpression(entity));
        if (existingEntity != null)
        {
            _context.Entry(existingEntity).CurrentValues.SetValues(entity);
            yield return existingEntity;
        }
        else
        {
            _context.Set<T>().Add(entity);
            yield return entity;
        }
    }
    _context.SaveChanges();
}

এটি আমাকে এটির মতো কল করতে এবং অন্তর্নিহিত সংগ্রহগুলি সন্নিবেশ / আপডেট করতে সহায়তা করে:

movie.Genres = new List<Genre>(InsertOrUpdate(movie.Genres, x => x.TmdbId));

লক্ষ্য করুন যে আমি কীভাবে পুনরুদ্ধারকৃত মানটিকে মূল মূল অবজেক্টে পুনঃস্থাপন করব: এখন এটি প্রতিটি সংযুক্ত বস্তুর সাথে সংযুক্ত। রুট অবজেক্ট আপডেট করা (মুভি) একইভাবে সম্পন্ন করা হয়:

var localMovie = _context.Movies.SingleOrDefault(x => x.TmdbId == movie.TmdbId);
if (localMovie == null)
{
    _context.Movies.Add(movie);
} 
else
{
    _context.Entry(localMovie).CurrentValues.SetValues(movie);
}

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

0

যেহেতু আপনি বিভিন্ন ক্ষেত্রের সাথে লেনদেন করছেন idএবং tmbid, আমি পরামর্শ দিচ্ছি যে জেনার, ভাষা, কীওয়ার্ড ইত্যাদির মতো সমস্ত তথ্যের একক এবং পৃথক সূচক তৈরি করতে API আপডেট করুন ... এবং তারপরে সূচকে কল করুন এবং সংগ্রহের পরিবর্তে তথ্য অনুসন্ধান করুন আপনার মুভি ক্লাসে নির্দিষ্ট অবজেক্ট সম্পর্কে সম্পূর্ণ তথ্য।


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