সম্পত্তির ডিফল্ট মানের মাধ্যমে সম্পর্ক পরিবর্তন করার চেষ্টা করার সময় অপ্রত্যাশিত অবৈধ অপারেশন ধারণা


10

নীচের নমুনা কোডটিতে আমি নিম্নলিখিত ব্যতিক্রমগুলি পেয়েছি db.Entry(a).Collection(x => x.S).IsModified = true:

System.InuthorOperationException: 'সত্তা টাইপ' B 'এর উদাহরণটি ট্র্যাক করা যায়নি কারণ মূল মান' {আইডি: 0} 'সহ অন্য একটি উদাহরণ ইতিমধ্যে ট্র্যাক করা হয়েছে। বিদ্যমান সত্তাগুলি সংযুক্ত করার সময়, নিশ্চিত হওয়া যে প্রদত্ত মূল মান সহ কেবল একটি সত্তা উদাহরণ সংযুক্ত রয়েছে।

এটি খ এর দৃষ্টান্ত সংযুক্ত করার পরিবর্তে কেন যুক্ত হয় না?

আশ্চর্যজনকভাবে এর জন্য ডকুমেন্টেশন কোনও সম্ভাব্য ব্যতিক্রম হিসাবে IsModifiedনির্দিষ্ট করে না InvalidOperationException। অবৈধ ডকুমেন্টেশন বা একটি বাগ?

আমি জানি এই কোডটি অদ্ভুত, তবে আমি কেবল কিছু অদ্ভুত উদাহরণের ক্ষেত্রে ইফ কোর কীভাবে কাজ করে তা বোঝার জন্য এটি লিখেছিলাম। আমি যা চাই তা হল একটি ব্যাখ্যা, চারপাশের কাজ নয়।

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    public class A
    {
        public int Id { get; set; }
        public ICollection<B> S { get; set; } = new List<B>() { new B {}, new B {} };
    }

    public class B
    {
        public int Id { get; set; }
    }

    public class Db : DbContext {
        private const string connectionString = @"Server=(localdb)\mssqllocaldb;Database=Apa;Trusted_Connection=True";

        protected override void OnConfiguring(DbContextOptionsBuilder o)
        {
            o.UseSqlServer(connectionString);
            o.EnableSensitiveDataLogging();
        }

        protected override void OnModelCreating(ModelBuilder m)
        {
            m.Entity<A>();
            m.Entity<B>();
        }
    }

    static void Main(string[] args)
    {
        using (var db = new Db()) {
            db.Database.EnsureDeleted();
            db.Database.EnsureCreated();

            db.Add(new A { });
            db.SaveChanges();
        }

        using (var db = new Db()) {
            var a = db.Set<A>().Single();
            db.Entry(a).Collection(x => x.S).IsModified = true;
            db.SaveChanges();
        }
    }
}

এ এবং বি কীভাবে সম্পর্কিত? মানে সম্পর্কের সম্পত্তি কী?
সাম

উত্তর:


8

প্রদত্ত কোডে ত্রুটির কারণ নিম্নলিখিত।

আপনি যখন Aডাটাবেস থেকে সত্তা তৈরি করেন তার সম্পত্তি Sদুটি নতুন রেকর্ড রয়েছে এমন একটি সংগ্রহের মাধ্যমে শুরু করা হয় BIdএই নতুন Bসত্ত্বার প্রত্যেকটির সমান 0

// This line of code reads entity from the database
// and creates new instance of object A from it.
var a = db.Set<A>().Single();

// When new entity A is created its field S initialized
// by a collection that contains two new instances of entity B.
// Property Id of each of these two B entities is equal to 0.
public ICollection<B> S { get; set; } = new List<B>() { new B {}, new B {} };

সত্তার কোড var a = db.Set<A>().Single()সংগ্রহের লাইন কার্যকর করার পরে ডাটাবেস থেকে সত্ত্বা থাকে না , কারণ অলস লোডিং ব্যবহার করে না এবং সংগ্রহের কোনও সুস্পষ্ট লোডিং নেই । সত্তা শুধুমাত্র নতুন ধারণ সত্ত্বা সংগ্রহ আরম্ভের সময় তৈরি হওয়া ।SABDbContext DbSABS

আপনি যখন IsModifed = trueসংগ্রহ Sসত্তার কাঠামোর জন্য কল করেন তখন সেই দুটি নতুন প্রবেশকে Bপরিবর্তন ট্র্যাকিংয়ের সাথে যুক্ত করার চেষ্টা করে । তবে এটি ব্যর্থ হয়েছে কারণ দুটি নতুন Bসত্তারই একই রকম Id = 0:

// This line tries to add to change tracking two new B entities with the same Id = 0.
// As a result it fails.
db.Entry(a).Collection(x => x.S).IsModified = true;

স্ট্যাক ট্রেস থেকে আপনি দেখতে পাচ্ছেন যে সত্তা কাঠামোটি Bসত্তাগুলিকে এতে সন্নিবেশ করার চেষ্টা করেছে IdentityMap:

at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.ThrowIdentityConflict(InternalEntityEntry entry)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.Add(TKey key, InternalEntityEntry entry, Boolean updateDuplicate)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.Add(TKey key, InternalEntityEntry entry)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.Add(InternalEntityEntry entry)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.StartTracking(InternalEntityEntry entry)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetPropertyModified(IProperty property, Boolean changeState, Boolean isModified, Boolean isConceptualNull, Boolean acceptChanges)
at Microsoft.EntityFrameworkCore.ChangeTracking.NavigationEntry.SetFkPropertiesModified(InternalEntityEntry internalEntityEntry, Boolean modified)
at Microsoft.EntityFrameworkCore.ChangeTracking.NavigationEntry.SetFkPropertiesModified(Object relatedEntity, Boolean modified)
at Microsoft.EntityFrameworkCore.ChangeTracking.NavigationEntry.set_IsModified(Boolean value)

এবং ত্রুটি বার্তাটি আরও বলেছে যে এটি Bসত্তার সাথে ট্র্যাক করতে পারে না Id = 0কারণ এর সাথে অন্য একটি Bসত্তা Idইতিমধ্যে ট্র্যাক করা হয়েছে।


কিভাবে এই সমস্যার সমাধান.

এই সমস্যার সমাধানের জন্য আপনার সংগ্রহটি Bআরম্ভ করার সময় সত্তা তৈরি করে এমন কোড মুছে ফেলা উচিত S:

public ICollection<B> S { get; set; } = new List<B>();

পরিবর্তে আপনার Sযেখানে Aতৈরি করা হয়েছে সেখানে সংগ্রহ পূরণ করা উচিত । উদাহরণ স্বরূপ:

db.Add(new A {S = {new B(), new B()}});

আপনি যদি অলস লোডিং ব্যবহার না Sকরেন তবে এর আইটেমগুলি পরিবর্তন ট্র্যাকিংয়ে যুক্ত করার জন্য আপনার সংগ্রহটি স্পষ্টভাবে লোড করা উচিত :

// Use eager loading, for example.
A a = db.Set<A>().Include(x => x.S).Single();
db.Entry(a).Collection(x => x.S).IsModified = true;

এটি খ এর দৃষ্টান্ত সংযুক্ত করার পরিবর্তে কেন যুক্ত হয় না?

সংক্ষেপে , তারা যুক্ত হওয়ার ইচ্ছার সাথে যুক্ত থাকে কারণ তাদের Detachedরাষ্ট্র রয়েছে।

কোড লাইন কার্যকর করার পরে

var a = db.Set<A>().Single();

সত্তার তৈরি দৃষ্টান্তগুলির Bরাষ্ট্র রয়েছে Detached। এটি পরবর্তী কোড ব্যবহার করে যাচাই করা যেতে পারে:

Console.WriteLine(db.Entry(a.S[0]).State);
Console.WriteLine(db.Entry(a.S[1]).State);

তারপর আপনি যখন সেট

db.Entry(a).Collection(x => x.S).IsModified = true;

EF Bট্র্যাকিং পরিবর্তন করতে সত্তা যুক্ত করার চেষ্টা করে । ইসিফোরের উত্স কোড থেকে আপনি দেখতে পাচ্ছেন যে এটি আমাদের অভ্যন্তরীণতা- এন্ট্রি পদ্ধতির দিকে নিয়ে যায় etসেটপ্রোপার্টিটি পরবর্তী যুক্তির মানগুলির সাথে সংশোধিত :

  • property- আমাদের Bসত্তার একটি,
  • changeState = true,
  • isModified = true,
  • isConceptualNull = false,
  • acceptChanges = true

এই জাতীয় যুক্তিযুক্ত এই পদ্ধতিটি Detached Bএন্টিগুলির স্থিতিতে পরিবর্তন করে Modifiedএবং তারপরে তাদের ট্র্যাকিং শুরু করার চেষ্টা করে (লাইন 490 - 506 দেখুন)। কারণ Bসত্তাগুলির এখন অবস্থা রয়েছে Modifiedএটি এগুলি সংযুক্ত হওয়ার দিকে পরিচালিত করে (যোগ করা হয়নি)।


"বি এর উদাহরণ সংযুক্ত করার পরিবর্তে এটি কেন যুক্ত হয় না?" এর উত্তর কোথায়? আপনি বলছেন "এটি ব্যর্থ হয়েছে কারণ দুটি নতুন বি সত্তার আইডি = 0 একই"। আমি মনে করি এটি ভুল কারণ ইফ কোর 1 এবং 2 আইডি উভয়ই সঞ্চয় করে। আমি মনে করি না যে এটি এই প্রশ্নের সঠিক উত্তর
DIlshod কে

@ ডিআইএলশড কে মন্তব্যের জন্য ধন্যবাদ। "এই সমস্যাটি কীভাবে সমাধান করবেন" বিভাগে আমি লিখেছিলাম যে সংগ্রহটি Sস্পষ্টভাবে লোড করা উচিত, কারণ প্রদত্ত কোডটি অলস লোডিং ব্যবহার করে না। অবশ্যই, EF Bডাটাবেসে পূর্বে তৈরি সত্তা সংরক্ষণ করেছিল saved কিন্তু কোডের লাইনটি সংগ্রহে A a = db.Set<A>().Single()সত্তা Aছাড়াই সত্তা লোড করে S। সংগ্রহ লোড Sকরতে আগ্রহী লোডিং ব্যবহার করা উচিত। আমি আমার asnver পরিবর্তন করব "বি এর উদাহরণ সংযুক্ত করার পরিবর্তে এটি কেন যুক্ত করে না?" এই প্রশ্নের উত্তর স্পষ্টভাবে অন্তর্ভুক্ত করতে।
ইলিয়র তুরদুশেভ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.