entity framework - इकाई फ्रेमवर्क 4.1+ कई से कई संबंध ट्रैकिंग बदलते हैं




entity-framework many-to-many (2)

मैं ICollection <> गुणों (कई से कई रिश्ते) के परिवर्तनों का पता कैसे लगा सकता हूं?

public class Company
{
    ...

    public virtual ICollection<Employee> Employees { get; set; }
}

using (DataContext context = new DataContext(Properties.Settings.Default.ConnectionString))
{
    Company company = context.Companies.First();
    company.Employees.Add(context.Employees.First());

    context.SaveChanges();
}

public class DataContext : DbContext
{
    public override int SaveChanges()
    {
        return base.SaveChanges();

        // Company's entity state is "Unchanged" in this.ChangeTracker
    }
}

मैं आपको अपनी स्थिति के लिए सटीक कोड नहीं दे सकता, लेकिन मैं आपको बता सकता हूं कि कई लोगों को कई रिश्तों को तोड़ने के लिए कर्मचारियों और कंपनी के बीच एक जॉइनर टेबल करके आपकी स्थिति दस गुना सरलीकृत की जाएगी।


यहां बताया गया है कि सभी बदले में कई सारे रिश्तों को कैसे ढूंढें। मैंने विस्तार विधियों के रूप में कोड लागू किया है:

public static class IaExtensions
{
    public static IEnumerable<Tuple<object, object>> GetAddedRelationships(
        this DbContext context)
    {
        return GetRelationships(context, EntityState.Added, (e, i) => e.CurrentValues[i]);
    }

    public static IEnumerable<Tuple<object, object>> GetDeletedRelationships(
        this DbContext context)
    {
        return GetRelationships(context, EntityState.Deleted, (e, i) => e.OriginalValues[i]);
    }

    private static IEnumerable<Tuple<object, object>> GetRelationships(
        this DbContext context,
        EntityState relationshipState,
        Func<ObjectStateEntry, int, object> getValue)
    {
        context.ChangeTracker.DetectChanges();
        var objectContext = ((IObjectContextAdapter)context).ObjectContext;

        return objectContext
            .ObjectStateManager
            .GetObjectStateEntries(relationshipState)
            .Where(e => e.IsRelationship)
            .Select(
                e => Tuple.Create(
                    objectContext.GetObjectByKey((EntityKey)getValue(e, 0)),
                    objectContext.GetObjectByKey((EntityKey)getValue(e, 1))));
    }
}

कुछ स्पष्टीकरण। स्वतंत्र संघों, या आईएएस के रूप में ईएफ में कई से अधिक संबंधों का प्रतिनिधित्व किया जाता है। ऐसा इसलिए है क्योंकि रिश्ते के लिए विदेशी कुंजी ऑब्जेक्ट मॉडल में कहीं भी नहीं उजागर होती हैं। डेटाबेस में एफके एक जॉइन टेबल में हैं, और यह शामिल तालिका ऑब्जेक्ट मॉडल से छिपी हुई है।

आईएएस को "रिलेशनशिप प्रविष्टियों" का उपयोग करके ईएफ में ट्रैक किया जाता है। ये DbEntityEntry ऑब्जेक्ट्स के समान हैं जो आप DbContext.Entry से प्राप्त करते हैं सिवाय इसके कि वे एक इकाई के बजाय दो इकाइयों के बीच संबंध का प्रतिनिधित्व करते हैं। रिलेशनशिप प्रविष्टियों को डीबीकॉन्टेक्स्ट एपीआई में उजागर नहीं किया जाता है, इसलिए आपको उन्हें एक्सेस करने के लिए ऑब्जेक्ट कॉन्टेक्स्ट पर छोड़ना होगा।

एक नई रिलेशनशिप एंट्री बनाई जाती है जब दो इकाइयों के बीच एक नया रिश्ता बनाया जाता है, उदाहरण के लिए कंपनी में कर्मचारी जोड़कर। कर्मचारी संग्रह। यह रिश्ता जोड़ा राज्य में है।

इसी तरह, जब दो इकाइयों के बीच संबंध हटा दिया जाता है, तो संबंध प्रविष्टि हटाए गए राज्य में डाल दी जाती है।

इसका मतलब यह है कि कई से अधिक रिश्तों को बदलना (या वास्तव में कोई भी बदला गया आईए) हमें जोड़ने और हटाए गए रिलेशनशिप प्रविष्टियों को खोजने की जरूरत है। GetAddedRelationships और GetDeletedRelationships यही करते हैं।

एक बार हमारे पास रिलेशनशिप प्रविष्टियां हो जाने के बाद, हमें उन्हें समझने की आवश्यकता है। इसके लिए आपको अंदरूनी ज्ञान के एक टुकड़े को जानने की जरूरत है। एक जोड़ा गया (या अपरिवर्तित) रिलेशनशिप प्रविष्टि की CurrentValues ​​प्रॉपर्टी में दो मान होते हैं जो संबंधों के किसी भी अंत में इकाइयों की EntityKey ऑब्जेक्ट्स होते हैं। इसी प्रकार, लेकिन कष्टप्रद थोड़ा अलग, हटाए गए रिलेशनशिप प्रविष्टि की मूल वैल्यू प्रॉपर्टी में हटाए गए रिश्ते के किसी भी अंत में इकाइयों के लिए EntityKey ऑब्जेक्ट्स शामिल हैं।

(और, हाँ, यह भयानक है। कृपया मुझे दोष न दें- यह मेरे समय से पहले से ही है।)

CurrentValues ​​/ OriginalValues ​​अंतर यह है कि हम GetRelationships निजी विधि में एक प्रतिनिधि को क्यों पास करते हैं।

एक बार हमारे पास EntityKey ऑब्जेक्ट्स हो जाने के बाद हम वास्तविक इकाई उदाहरण प्राप्त करने के लिए GetObjectByKey का उपयोग कर सकते हैं। हम इन्हें टुपल्स के रूप में वापस करते हैं और वहां आपके पास है।

यहां कुछ संस्थाएं, एक संदर्भ, और प्रारंभकर्ता है, मैं इसका परीक्षण करता था। (नोट-परीक्षण व्यापक नहीं था।)

public class Company
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Employee> Employees { get; set; }

    public override string ToString()
    {
        return "Company " + Name;
    }
}

public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Company> Companies { get; set; }

    public override string ToString()
    {
        return "Employee " + Name;
    }
}

public class DataContext : DbContext
{
    static DataContext()
    {
        Database.SetInitializer(new DataContextInitializer());
    }

    public DbSet<Company> Companies { get; set; }
    public DbSet<Employee> Employees { get; set; }

    public override int SaveChanges()
    {
        foreach (var relationship in this.GetAddedRelationships())
        {
            Console.WriteLine(
                "Relationship added between {0} and {1}",
                relationship.Item1,
                relationship.Item2);
        }

        foreach (var relationship in this.GetDeletedRelationships())
        {
            Console.WriteLine(
                "Relationship removed between {0} and {1}",
                relationship.Item1,
                relationship.Item2);
        }

        return base.SaveChanges();
    }

}

public class DataContextInitializer : DropCreateDatabaseAlways<DataContext>
{
    protected override void Seed(DataContext context)
    {
        var newMonics = new Company { Name = "NewMonics", Employees = new List<Employee>() };
        var microsoft = new Company { Name = "Microsoft", Employees = new List<Employee>() };

        var jim = new Employee { Name = "Jim" };
        var arthur = new Employee { Name = "Arthur" };
        var rowan = new Employee { Name = "Rowan" };

        newMonics.Employees.Add(jim);
        newMonics.Employees.Add(arthur);
        microsoft.Employees.Add(arthur);
        microsoft.Employees.Add(rowan);

        context.Companies.Add(newMonics);
        context.Companies.Add(microsoft);
    }
}

इसका उपयोग करने का एक उदाहरण यहां दिया गया है:

using (var context = new DataContext())
{
    var microsoft = context.Companies.Single(c => c.Name == "Microsoft");
    microsoft.Employees.Add(context.Employees.Single(e => e.Name == "Jim"));

    var newMonics = context.Companies.Single(c => c.Name == "NewMonics");
    newMonics.Employees.Remove(context.Employees.Single(e => e.Name == "Arthur"));

    context.SaveChanges();
} 






change-tracking