2012-11-20 33 views
7

का उपयोग करके संग्रह से किसी आइटम को निकालें I डीडीडी का उपयोग कर रहा हूं। मेरे पास एक वर्ग उत्पाद है जो एक समग्र रूट है।एंटिटी फ्रेमवर्क

public class Product : IAggregateRoot 
{ 
    public virtual ICollection<Comment> Comments { get; set; } 

    public void AddComment(Comment comment) 
    { 
     Comments.Add(comment); 
    } 

    public void DeleteComment(Comment comment) 
    { 
     Comments.Remove(comment); 
    } 
} 

मॉडल जो परत रखती है वह ईएफ के बारे में नहीं जानता है। समस्या यह है कि जब मैं DeleteComment(comment) पर कॉल करता हूं, तो ईएफ अपवाद

'Product_Comments' एसोसिएशनसेट से एक संबंध 'हटाए गए' राज्य में है। बहुगुणित बाधाओं को देखते हुए, 'हटाए गए' राज्य में एक संबंधित 'product_Comments_Target' भी होना चाहिए।

भले ही तत्व संग्रह से हटा दिया गया हो, ईएफ इसे हटा नहीं देता है। डीडीडी तोड़ने के बिना इसे ठीक करने के लिए मुझे क्या करना चाहिए? (मैं टिप्पणियाँ रूप में अच्छी तरह के लिए भंडार बनाने की सोच रहा हूँ, लेकिन सही नहीं है)

कोड उदाहरण:

क्योंकि मैं DDD उपयोग करने के लिए कोशिश कर रहा हूँ, Product एक समग्र जड़ है, और यह एक है भंडार IProductRepository। एक टिप्पणी उत्पाद के बिना मौजूद नहीं हो सकती है, इसलिए Product कुल बच्चे हैं, और Product टिप्पणियां बनाने और हटाने के लिए ज़िम्मेदार है। Comment में रिपोजिटरी नहीं है।

public class ProductService 
{ 
    public void AddComment(Guid productId, string comment) 
    { 
     Product product = _productsRepository.First(p => p.Id == productId); 
     product.AddComment(new Comment(comment)); 
    } 

    public void RemoveComment(Guid productId, Guid commentId) 
    { 
     Product product = _productsRepository.First(p => p.Id == productId); 
     Comment comment = product.Comments.First(p => p.Id == commentId); 
     product.DeleteComment(comment); 


     // Here i get the error. I am deleting the comment from Product Comments Collection, 
     // but the comment does not have the 'Deleted' state for Entity Framework to delete it 

     // However, i can't change the state of the Comment object to 'Deleted' because 
     // the Domain Layer does not have any references to Entity Framework (and it shouldn't) 

     _uow.Commit(); // UnitOfWork commit method 

    } 
} 
+1

ऐसा लगता है कि आप ईएफ के सेव चेंज को कॉल नहीं कर रहे हैं – Nagg

+0

मुझे लगता है कि लक्ष्य नामक एक टेबल है। इस तालिका में टिप्पणियाँ तालिका के लिए एफके संदर्भ है। जब आप टिप्पणी तालिका में एक पंक्ति को हटाने का प्रयास करते हैं, तो लक्ष्य में सहयोगी पंक्तियों को पहले हटाने की आवश्यकता होती है। –

+0

@Nagg मुझे यह त्रुटि मिलती है जब मैं SubmitChanges() – Catalin

उत्तर

1

आपके दृष्टिकोण का उपयोग करके उत्पाद से टिप्पणी हटाने से केवल उत्पाद और टिप्पणी के बीच संबंध हटा दिया जाता है। ताकि टिप्पणी अभी भी मौजूद हो।

ऑब्जेक्ट कॉन्टेक्स्ट को बताने के लिए आपको क्या करना है कि टिप्पणी DeleteObject() विधि का उपयोग करके भी हटा दी गई है।

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

public void UpdateProduct(Product product) { 
    var modifiedStateEntries = Context.ObjectStateManager.GetObjectStateEntries(EntityState.Modified); 
    foreach (var entry in modifiedStateEntries) { 
     var comment = entry.Entity as Comment; 
     if (comment != null && comment.Product == null) { 
     Context.DeleteObject(comment); 
     } 
    } 
} 

नमूना:

Delete Dependent Entities When Removed From EF Collection

+0

एक समान समस्या थी - DeleteObject() एक आकर्षण की तरह काम करता है। –

+0

नहीं, आपको Context.ObjectStateManager को स्पर्श करने की आवश्यकता नहीं है और मैं दृढ़ता से आपको संदर्भ के राज्य के साथ खेलने के लिए सलाह नहीं देता, जब तक कि आपके पास ऐसा करने का वास्तविक कारण न हो। इस समस्या को हल करने के लिए, आपको बच्चे पर एक समग्र कुंजी सेट करने की आवश्यकता होगी। इस तरह, जब आप अपने माता-पिता से बच्चे को हटा देते हैं, तो ईएफ रिश्ते को हटा देगा और बच्चे की इकाई को भी हटा देगा। कोड उदाहरण के लिए नीचे मेरा जवाब देखें। – Mosh

0

मैं अपने मॉडल के लिए एक माता पिता के गुण पैदा करने और विशेषता की जाँच करके एक ही समस्या का समाधान कर लिया:

public void RemoveComment(Guid productId, Guid commentId) { 
    Product product = _productsRepository.First(p => p.Id == productId); 
    Comment comment = product.Comments.First(p => p.Id == commentId); 
    product.DeleteComment(comment); 

    _productsRepository.Update(product); 

    _uow.Commit(); 
} 
11

मैंने इस मुद्दे की रिपोर्ट करने वाले बहुत से लोगों को देखा है। यह वास्तव में ठीक करने के लिए काफी आसान है लेकिन मुझे लगता है कि इस स्थिति में ईएफ से व्यवहार करने की अपेक्षा करने के लिए पर्याप्त दस्तावेज नहीं है।

चाल: माता-पिता और बच्चे के बीच संबंध स्थापित करते समय, आपको बच्चे पर "समग्र" कुंजी बनाना होगा। इस तरह, जब आप माता-पिता को 1 या उसके सभी बच्चों को हटाने के लिए कहते हैं, तो संबंधित रिकॉर्ड वास्तव में डेटाबेस से हटा दिए जाएंगे।तब

modelBuilder.Entity<Child>.HasKey(t => new { t.ParentId, t.ChildId }); 

, संबंधित बच्चों को हटाने के लिए:

Fluent एपीआई का उपयोग कर समग्र कुंजी कॉन्फ़िगर करने के लिए

var parent = _context.Parents.SingleOrDefault(p => p.ParentId == parentId); 

var childToRemove = parent.Children.First(); // Change the logic 
parent.Children.Remove(childToRemove); 

// or, you can delete all children 
// parent.Children.Clear(); 

_context.SaveChanges(); 

हो गया!

2

मैं 3 दृष्टिकोण देखा है एफई में इस कमी को वैकल्पिक हल के लिए:

  1. कॉन्फ़िगर (Mosh के जवाब के अनुसार) एक समग्र कुंजी
  2. एक डोमेन घटना उठाएँ और एफई हिदायत में बच्चे विलोपन प्रदर्शन करने के लिए अपने हैंडलर (प्रति this जवाब के रूप में)
  3. अवहेलना DbContext के SaveChanges() और वहाँ विलोपन संभाल (जश्न के जवाब के अनुसार)

मुझे विकल्प 3 सबसे अच्छा पसंद है क्योंकि इसे आपके डेटाबेस संरचना (1) या आपके डोमेन मॉडल (2) में संशोधन की आवश्यकता नहीं है, लेकिन घटक (ईएफ) में वर्कअराउंड रखता है जिसमें पहली जगह की कमी थी।

public class MyDbContext : DbContext 
{ 
    //... typical DbContext stuff 

    public DbSet<Product> ProductSet { get; set; } 
    public DbSet<Comment> CommentSet { get; set; } 

    //... typical DbContext stuff 


    public override int SaveChanges() 
    { 
     MonitorForAnyOrphanedCommentsAndDeleteThemIfRequired(); 
     return base.SaveChanges(); 
    } 

    public override Task<int> SaveChangesAsync() 
    { 
     MonitorForAnyOrphanedCommentsAndDeleteThemIfRequired(); 
     return base.SaveChangesAsync(); 
    } 

    public override Task<int> SaveChangesAsync(CancellationToken cancellationToken) 
    { 
     MonitorForAnyOrphanedCommentsAndDeleteThemIfRequired(); 
     return base.SaveChangesAsync(cancellationToken); 
    } 

    private void MonitorForAnyOrphanedCommentsAndDeleteThemIfRequired() 
    { 
     var orphans = ChangeTracker.Entries().Where(e => 
      e.Entity is Comment 
      && (e.State == EntityState.Modified || e.State == EntityState.Added) 
      && (e.Entity as Comment).ParentProduct == null); 

     foreach (var item in orphans) 
      CommentSet.Remove(item.Entity as Comment); 
    } 
} 

नोट::

तो यह जश्न का जवाब/ब्लॉग पोस्ट से ली गई एक अद्यतन हल है इस मानता है कि ParentProduct अपने मालिक Product करने के लिए Comment पीठ पर नेविगेशन संपत्ति है।

संबंधित मुद्दे