2013-07-22 15 views
9

के साथ इकाइयों को जोड़ना और अपडेट करना मेरे आखिरी प्रोजेक्ट में मैंने एंटीटी फ्रेमवर्क 5 कोड फर्स्ट का उपयोग किया है। मैंने अपनी परियोजना पूरी की लेकिन विकास प्रक्रिया के दौरान बहुत दर्द हुआ।इकाई फ्रेमवर्क

मैं अपने दर्द को समझाने के लिए नीचे की कोशिश की:

मैं उत्पाद, ProductCategory, आदेश, कंपनी, निर्माता आदि की तरह मेरे डेटा का उपयोग तर्क परत में कई डेटा वर्गों था ... प्रत्येक वर्ग कुछ अन्य वर्गों के लिए कुछ संदर्भों है । उदाहरण के लिए, एक उत्पाद उदाहरण में ProductCategory प्रॉपर्टी होती है।

मेरे डेटा एक्सेस ऑब्जेक्ट क्लास के अंदर और अपडेट विधियों के अंदर मैंने प्रत्येक संपत्ति के राज्य (आदिम प्रकारों के अलावा) को अपरिवर्तित या संदर्भ में संशोधित करने के लिए सेट किया है।

context.Entry(entity).State = System.Data.EntityState.Modified; 
if (entity.Category != null) 
    context.Entry(entity.Category).State = System.Data.EntityState.Unchanged; 

if (entity.Manufacturer != null) 
    context.Entry(entity.Manufacturer).State = System.Data.EntityState.Unchanged; 

foreach (var specificationDefinition in entity.SpecificationDefinitions) 
{ 
    context.Entry(specificationDefinition).State = System.Data.EntityState.Unchanged; 
    foreach (var specificationValue in specificationDefinition.Values) 
    { 
     context.Entry(specificationValue).State = System.Data.EntityState.Unchanged; 
    } 
} 

इस कोड को इस प्रकार है: नीचे कुछ दाव वर्ग के एक अद्यतन विधि का कुछ हिस्सा है। मेरे कुछ जोड़ या अद्यतन विधियां कोड की लगभग 30 पंक्तियां हैं। मुझे लगता है कि मैं कुछ गलत कर रहा हूं, किसी इकाई को जोड़ना या अपडेट करना इतना दर्द नहीं होना चाहिए, लेकिन जब मैं वस्तुओं के राज्यों को सेट नहीं करता हूं तो मुझे डेटाबेस में अपवाद या डुप्लिकेट प्रविष्टियां मिलती हैं। क्या मुझे वास्तव में प्रत्येक प्रॉपर्टी की स्थिति सेट करना है जो डेटाबेस में मैप करता है?

+0

क्या आप वह कोड जोड़ सकते हैं जिसमें आप डेटा बनाते हैं? यदि आपकी कक्षाओं में आपके संदर्भ सही हैं, तो ईएफ को केवल एक बार सभी उदाहरण बनाना चाहिए। – Nullius

+0

हां यह एक ही समय में सभी उदाहरण बनाता है। वास्तव में यह समस्या है। मुझे फिर से समस्या की व्याख्या करने दो। मान लें कि मेरे पास उत्पाद का एक उदाहरण है जिसमें इसके अंदर एक उत्पाद प्रकार उदाहरण है। मान लें कि अतीत में उत्पाद उदाहरण पहले से ही जारी है। जब मैं उस उत्पाद आवृत्ति को अद्यतन करने का प्रयास करता हूं, तो ईएफ एक डुप्लिकेट उत्पाद प्रकार उदाहरण बनाता है (जो एक ऐसा मामला है जिसे मैं नहीं चाहता) अगर मैं उत्पाद प्रकार की स्थिति को अपरिवर्तित नहीं करता हूं। – Furkan

उत्तर

11

आप के द्वारा अपने कोड के स्थान पर कर सकते हैं:

context.Products.Attach(entity); 
context.Entry(entity).State = System.Data.EntityState.Modified; 

कारण है कि यह एक ही है (जब तक संबंधित संस्थाएं पहले से ही Unchanged की तुलना में किसी अन्य राज्य में संदर्भ से जुड़ी हुई थीं) Attachentity राज्य Unchanged में संदर्भ में ऑब्जेक्ट ग्राफ़ में सभी संबंधित इकाइयां शामिल हैं। entity के लिए राज्य को Modified पर सेट करने के लिए Unchanged से Modified पर केवल उत्पाद की स्थिति (संबंधित संस्थाओं) को ही बदलती है।

+0

यह तब काम नहीं करेगा जब इकाई किसी अन्य (अभी तक निपटान नहीं) संदर्भ से पुनर्प्राप्त की गई हो। आपको इसके बारे में अपवाद मिलेगा। –

+0

@MichaelLogutov: आप सही हैं, लेकिन मुझे पूरा विश्वास है कि प्रश्न में परिदृश्य एक अलग परिदृश्य है (यानी पहले का संदर्भ पहले से ही निपटाया गया है)। अन्यथा यह किसी भी इकाई राज्यों के साथ सामान्य रूप से परेशान नहीं होने के कारण भी बहुत आसान है क्योंकि परिवर्तन ट्रैकिंग स्वचालित राज्यों का स्वचालित रूप से ट्रैक रखेगी। – Slauma

3

ठीक है, तो आप बस कुछ गलत कर रहे हैं। मेरी टिप्पणी के अलावा, मैंने आपके लिए एक नमूना बनाया है जो दिखाता है कि ईएफ डिफ़ॉल्ट रूप से डुप्लिकेट नहीं बनाता है।

public class Product 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public ProductCategory Category { get; set; } 
    public decimal Price { get; set; } 
} 

public class ProductCategory 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

एक संदर्भ:

public class MyContext : DbContext 
{ 
    public DbSet<Product> Products { get; set; } 
    public DbSet<ProductCategory> ProductCategories { get; set; } 

    public MyContext() 
     : base("name=MyContext") 
    { 
    } 

    public MyContext(string nameOrConnectionString) 
     : base(nameOrConnectionString) 
    { 
    } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     Database.SetInitializer<MyContext>(null); 

     // Table mappings 
     modelBuilder.Entity<Product>().ToTable("Product"); 
     modelBuilder.Entity<ProductCategory>().ToTable("ProductCategory"); 

     base.OnModelCreating(modelBuilder); 
    } 
} 

फिर एक प्रारंभकर्ता वर्ग (इस अन्य रणनीतियों से विरासत सकता है अगर आप चाहते हैं):

public class InitDb<TContext> : DropCreateDatabaseAlways<TContext> 
    where TContext : DbContext 
{ 
} 

मैं दो वर्गों है मुख्य कार्यक्रम:

static void Main(string[] args) 
    { 
     var prodCat = new ProductCategory() 
     { 
      Name = "Category 1" 
     }; 

     var prod = new Product() 
     { 
      Name = "Product 1", 
      Category = prodCat, 
      Price = 19.95M 
     }; 

     using (var context = new MyContext()) 
     { 
      var initializer = new InitDb<MyContext>(); 
      initializer.InitializeDatabase(context); 

      Console.WriteLine("Adding products and categories to context."); 
      context.ProductCategories.Add(prodCat); 
      context.Products.Add(prod); 

      Console.WriteLine(); 
      Console.WriteLine("Saving initial context."); 
      context.SaveChanges(); 
      Console.WriteLine("Context saved."); 

      Console.WriteLine(); 
      Console.WriteLine("Changing product details."); 
      var initProd = context.Products.Include(x => x.Category).SingleOrDefault(x => x.Id == 1); 
      PrintProduct(initProd); 
      initProd.Name = "Product 1 modified"; 
      initProd.Price = 29.95M; 
      initProd.Category.Name = "Category 1 modified"; 
      PrintProduct(initProd); 

      Console.WriteLine(); 
      Console.WriteLine("Saving modified context."); 
      context.SaveChanges(); 
      Console.WriteLine("Context saved."); 

      Console.WriteLine(); 
      Console.WriteLine("Getting modified product from database."); 
      var modProd = context.Products.Include(x => x.Category).SingleOrDefault(x => x.Id == 1); 
      PrintProduct(modProd); 

      Console.WriteLine(); 
      Console.WriteLine("Finished!"); 
      Console.ReadKey(); 
     } 


    } 

    static void PrintProduct(Product prod) 
    { 
     Console.WriteLine(new string('-', 10)); 
     Console.WriteLine("Id  : {0}", prod.Id); 
     Console.WriteLine("Name : {0}", prod.Name); 
     Console.WriteLine("Price : {0}", prod.Price); 
     Console.WriteLine("CatId : {0}", prod.Category.Id); 
     Console.WriteLine("CatName : {0}", prod.Category.Name); 
     Console.WriteLine(new string('-', 10)); 
    } 

यह निम्न सांत्वना उत्पादन में परिणाम है:

Adding products and categories to context. 

Saving initial context. 
Context saved. 

Changing product details. 
---------- 
Id  : 1 
Name : Product 1 
Price : 19,95 
CatId : 1 
CatName : Category 1 
---------- 
---------- 
Id  : 1 
Name : Product 1 modified 
Price : 29,95 
CatId : 1 
CatName : Category 1 modified 
---------- 

Saving modified context. 
Context saved. 

Getting modified product from database. 
---------- 
Id  : 1 
Name : Product 1 modified 
Price : 29,95 
CatId : 1 
CatName : Category 1 modified 
---------- 

Finished! 

इसके अलावा, जब SQL सर्वर प्रबंधन स्टूडियो में देख, यह समाधान केवल बनाया गया है (और अद्यतन) एक उत्पाद है और एक श्रेणी।

संभोग, आपको अपने डेटा को पुनर्प्राप्त, अपडेट और हटाने और काम की इकाई को हटाने के लिए भंडारों के साथ काम करना चाहिए। इन्हें उदाहरण से बाहर कर दिया गया है।

तो, अगर आप किसी भी कोड पोस्ट न करें, हम आपकी सहायता नहीं कर बहुत आगे :-)

+0

उपरोक्त आपका कोड ईएफ कोड पहला दृष्टिकोण है? – Thomas

+0

@ थॉमस: यह वास्तव में पहले कोड है। – Nullius