2011-10-05 10 views
41

इकाई फ्रेमवर्क 4.1 कोड पहले महान बनाने वाली टेबल और रिश्तों को काम करता है। क्या कोड पहले दृष्टिकोण का उपयोग कर एसक्यूएल दृश्य या संग्रहीत प्रक्रिया बनाना संभव है? इसके बारे में किसी भी संकेतक की अत्यधिक सराहना की जाएगी। आपका बहुत बहुत धन्यवाद!क्या आप इकाई फ्रेमवर्क 4.1 कोड का उपयोग कर एसक्यूएल व्यू/संग्रहीत प्रक्रिया बना सकते हैं पहला दृष्टिकोण

उत्तर

9

ईएफ कोड-प्रथम दृष्टिकोण अपेक्षा करता है कि डेटाबेस में कोई तर्क नहीं है। इसका मतलब है कि कोई संग्रहित प्रक्रिया नहीं है और कोई डेटाबेस दृश्य नहीं है। उस कोड-प्रथम दृष्टिकोण के कारण स्वचालित रूप से आपके लिए ऐसी संरचनाएं उत्पन्न करने के लिए कोई तंत्र प्रदान नहीं करता है। यह कैसे कर सकता है अगर इसका अर्थ तर्क उत्पन्न करना है?

आपको मैन्युअल रूप से निर्माण स्क्रिप्ट निष्पादित करके custom database initializer में स्वयं को बनाना होगा। मुझे नहीं लगता कि इस कस्टम एसक्यूएल संरचनाओं को एसक्यूएल माइग्रेशन द्वारा नियंत्रित किया जा सकता है।

+0

हां - ईएफ कोड में एक दृश्य के समतुल्य पहले डेटा की प्रति के साथ एक तालिका है। आपका कोड उस द्वितीयक तालिका को बनाए रखने के लिए ज़िम्मेदार है। –

+17

असहमत होने के लिए खेद है लेकिन संग्रहीत प्रक्रियाओं को भी बनाया जाना चाहिए, इसलिए मेरे परिप्रेक्ष्य से यह एक गुम सुविधा है, और इसे जोड़ा जाना चाहिए। संग्रहीत प्रक्रिया डेटाबेस का हिस्सा हैं और विचार भी हैं। यह सच है कि उन्हें कभी भी इस्तेमाल नहीं किया जाना चाहिए, लेकिन वे मौजूद हैं और उन्हें डेटाबेस के विश्व में पहले नागरिकों के रूप में माना जाना चाहिए –

+3

@ यूजीनियोरो: हाँ यह सच है लेकिन ऐसे मामले में आपको डेटाबेस के पहले दृष्टिकोण का उपयोग करना चाहिए पहले कोड यदि आप डेटाबेस तर्क बनाना चाहते हैं तो ऐसा करें लेकिन इसे सीधे डेटाबेस में करें और ईएफ को उस दिशा से मॉडल को विपरीत दिशा में हैक करने की बजाय मॉडल बनाएं। –

1

Ladislav के रूप में बताया, सामान्य रूप में DbContext डेटाबेस में तर्क को कम से कम करने की प्रवृत्ति नहीं है, लेकिन यह context.Database.ExecuteSqlCommand() या context.Database.SqlQuery() का उपयोग करके कस्टम एसक्यूएल निष्पादित करने के लिए संभव है।

67

हम अपने इकाई फ्रेमवर्क कोड प्रथम माइग्रेशन में संग्रहित प्रक्रियाओं का समर्थन करते हैं। हमारा दृष्टिकोण है .sql फ़ाइलों को पकड़ने के लिए कुछ फ़ोल्डर बनाना (~/वर्ग/उदाहरण के लिए)। संग्रहीत प्रक्रिया को बनाने और छोड़ने के लिए फ़ोल्डर में .sql फ़ाइलों को बनाएँ। जैसे Create_sp_DoSomething.sql और Drop_sp_DoSomething। चूंकि एसक्यूएल बैच में चलता है और CREATE PROCEDURE.. बैच में पहला कथन होना चाहिए, तो फ़ाइल में पहला कथन CREATE PROCEDURE... बनाएं। इसके अलावा, DROP... के बाद GO डालें। यदि आपके पास पहले से कोई नहीं है, तो अपनी प्रोजेक्ट में संसाधन फ़ाइल जोड़ें। समाधान डिजाइनर से .sql फ़ाइलों को संसाधन डिजाइनर के फ़ाइलों दृश्य में खींचें।

namespace MyApplication.Migrations 
{ 
    using System; 
    using System.Data.Entity.Migrations; 

    public partial class SomethingMeaningful_sp_DoSomething : DbMigration 
    { 
     public override void Up() 
     { 
      this.Sql(Properties.Resources.Create_sp_DoSomething); 
     } 

     public override void Down() 
     { 
      this.Sql(Properties.Resources.Drop_sp_DoSomething); 
     } 
    } 
} 

~/Sql/Create_sp_DoSomething.sql

CREATE PROCEDURE [dbo].[sp_DoSomething] AS 
BEGIN TRANSACTION 
-- Your stored procedure here 
COMMIT TRANSACTION 
GO 

~/Sql/Drop_sp_DoSomething.sql

DROP PROCEDURE [dbo].[sp_DoSomething] 
+0

मुझे संसाधन की आवश्यकता क्यों है? – majkinetor

+1

आप नहीं करते हैं। आपको बस एसक्यूएल की जरूरत है। मैंने इसे एक फाइल में संग्रहीत किया और इसे प्रोग्राम में एक्सेस करने के लिए संसाधन के रूप में जोड़ा। आप एसक्यूएल को ऊपर/नीचे विधियों में एक स्ट्रिंग के रूप में डाल सकते हैं। –

+0

फ़ाइल संसाधन का उपयोग नहीं करना बेहतर है, लेकिन स्ट्रिंग संसाधन। फाइलें जुड़ी हुई हैं, इसलिए सभी माइग्रेशन संसाधनों पर परिवर्तन का प्रचार किया जाता है। यदि आप संग्रहीत प्रक्रियाओं को स्ट्रिंग के रूप में एम्बेड करते हैं, तो आप माइग्रेशन में प्रक्रियाओं को जोड़ने, ड्रॉप करने, बदलने और अनलटर करने के लिए resouce का उपयोग कर सकते हैं। मैंने इसे लागू करने के लिए आपकी विधि का उपयोग किया और यह ठीक काम करता है। Create_procedure() और दोस्तों को लागू करने के लिए मेरी विविधता डीबी माइग्रेशन क्लास पर एक्सटेंशन का उपयोग करती है। – majkinetor

21

: अब एक खाली माइग्रेशन (Add-Migration SomethingMeaningful_sp_DoSomething) और उपयोग बनाने पहली नजर में मुझे वास्तव में कार्ल जी के दृष्टिकोण पसंद हैं लेकिन इसमें बहुत सी मैन्युअल बातचीत शामिल है। मेरे परिदृश्य में, मैं हमेशा संग्रहीत प्रक्रियाओं, विचारों ... को छोड़ देता हूं और डेटाबेस में कोई परिवर्तन होने पर उन्हें फिर से बना देता हूं। इस तरह हम सुनिश्चित हैं कि सब कुछ नवीनतम संस्करण के साथ अद्यतित है।

मनोरंजन निम्नलिखित प्रारंभकर्ता की स्थापना द्वारा होता है:

Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, Configuration>()); 

तो हमारे बीज विधि जब भी एक प्रवास के लिए तैयार है कहा जाता हो जाएगा

protected override void Seed(DeploymentLoggingContext context) 
    { 
     // Delete all stored procs, views 
     foreach (var file in Directory.GetFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Sql\\Seed"), "*.sql")) 
     { 
      context.Database.ExecuteSqlCommand(File.ReadAllText(file), new object[0]); 
     } 

     // Add Stored Procedures 
     foreach (var file in Directory.GetFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Sql\\StoredProcs"), "*.sql")) 
     { 
      context.Database.ExecuteSqlCommand(File.ReadAllText(file), new object[0]); 
     } 
    } 

एसक्यूएल बयान आसान के लिए * .sql फाइलों में जमा हो जाती है संपादन। सुनिश्चित करें कि आपकी फ़ाइलों में "सामग्री बनाएं" और "आउटपुट निर्देशिका में कॉपी करें" पर सेट "बिल्ड एक्शन" है, "हमेशा कॉपी करें" पर सेट करें। हम फ़ोल्डर को देखते हैं और अंदर सभी स्क्रिप्ट निष्पादित करते हैं। अपने एसक्यूएल में "जाओ" कथन को बाहर करने के लिए मत भूलना क्योंकि उन्हें ExecuteSqlCommand() के साथ निष्पादित नहीं किया जा सकता है।

परियोजना:

मेरे वर्तमान निर्देशिका लेआउट इस प्रकार है।दाल
+ माइग्रेशन
+ Sql
++ बीज
+++ dbo.cleanDb.sql
++ StoredProcs
+++ dbo.sp_GetSomething.sql

अब आप की जरूरत है फ़ोल्डर में अतिरिक्त संग्रहित प्रक्रियाओं को छोड़ दें और सब कुछ उचित रूप से अपडेट हो जाएगा।

+1

साझा करने के लिए धन्यवाद। यह वही है जो मैं करने की कोशिश कर रहा हूं। –

+1

अच्छा जवाब है, लेकिन ड्रॉप और इंडेक्स बनाते हैं? हर बार ऐप चलता है? वास्तव में? –

+0

@MartinCapodici अच्छा पकड़ है, मुझे लगता है कि आवश्यक है – emp

2

एएमपी का डिज़ाइन एक चैंपियन की तरह काम करता है! मैं अपने पैटर्न का उपयोग कर रहा हूं लेकिन मैं अपने डीबीकॉन्टेक्स्ट क्लास के अंदर संग्रहित प्रक्रियाओं को भी मैप करता हूं जो SqlQuery() का उपयोग करने और प्रक्रियाओं को सीधे मेरे भंडार से कॉल करने के बजाय उन संदर्भ विधियों को कॉल करने की अनुमति देता है। चूंकि एप्लिकेशन बढ़ने पर चीजें थोड़ा बालों वाली हो सकती हैं, इसलिए मैंने अपनी बीज विधि के भीतर एक चेक बनाया है जो सुनिश्चित करता है कि वास्तविक संग्रहीत प्रक्रिया पैरामीटर गणना मैपिंग विधि पर पैरामीटर गिनती से मेल खाती है। मैंने डीआरओपी पाश एएमपी का भी उल्लेख किया है। ड्रॉप स्टेटमेंट्स के लिए एक अलग फ़ोल्डर/फ़ाइल को बनाए रखने के बजाय, मैं बस प्रत्येक एसक्यूएल फ़ाइल की पहली पंक्ति पढ़ता हूं और CREATE को DROP के साथ प्रतिस्थापित करता हूं (केवल सुनिश्चित करें कि पहली पंक्ति हमेशा CREATE PROCEDURE ProcName है)। इस तरह मेरे StoredProcs फ़ोल्डर में सभी प्रक्रियाओं को गिरा दिया जाता है और प्रत्येक बार अद्यतन-डेटाबेस चलाया जाता है। प्रक्रिया नई है, तो ड्रॉप को पकड़ने वाले ब्लॉक में भी लपेटा जाता है। प्रक्रिया पैरामीटर काम करने के लिए गिनती के लिए, आपको यह सुनिश्चित करना होगा कि आप अपने tsql के आस-पास BEGIN/END ब्लॉक को लपेटें क्योंकि फ़ाइल की प्रत्येक पंक्ति BEGIN तक पढ़ी जाती है। यह भी सुनिश्चित करें कि प्रत्येक स्पैम पैरामीटर नई लाइन पर है।

 // Drop Stored Procs 
     foreach (var file in Directory.GetFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..\\DataContext\\SiteMigrations\\StoredProcs"), "*.sql")) 
     { 
      // Try to drop proc if its already created 
      // Without this, for new procs, seed method fail on trying to delete 
      try 
      { 
       StreamReader reader = new StreamReader(file); 
       // Read first line of file to create drop command (turning CREATE [dbo].[TheProc] into DROP [dbo].[TheProc]) 
       string dropCommand = reader.ReadLine().Replace("CREATE", "DROP"); 

       context.Database.ExecuteSqlCommand(dropCommand, new object[0]); 
      } 
      catch { } 

     } 

     // Add Stored Procs 
     foreach (var file in Directory.GetFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..\\DataContext\\SiteMigrations\\StoredProcs"), "*.sql")) 
     { 
      // File/Proc names must match method mapping names in DbContext 
      int lastSlash = file.LastIndexOf('\\'); 
      string fileName = file.Substring(lastSlash + 1); 
      string procName = fileName.Substring(0, fileName.LastIndexOf('.')); 

      // First make sure proc mapping in DbContext contain matching parameters. If not throw exception. 
      // Get parameters for matching mapping 
      MethodInfo mi = typeof(SiteContext).GetMethod(procName); 

      if (mi == null) 
      { 
       throw new Exception(String.Format("Stored proc mapping for {0} missing in DBContext", procName)); 
      } 

      ParameterInfo[] methodParams = mi.GetParameters(); 
      // Finished getting parameters 

      // Get parameters from stored proc 
      int spParamCount = 0; 
      using (StreamReader reader = new StreamReader(file)) 
      { 
       string line;      
       while ((line = reader.ReadLine()) != null) 
       { 
        // If end of parameter section, break out 
        if (line.ToUpper() == "BEGIN") 
        { 
         break; 
        } 
        else 
        { 
         if (line.Contains("@")) 
         { 
          spParamCount++; 
         } 
        }       
       } 
      } 
      // Finished get parameters from stored proc 

      if (methodParams.Count() != spParamCount) 
      { 
       string err = String.Format("Stored proc mapping for {0} in DBContext exists but has {1} parameter(s)" + 
        " The stored procedure {0} has {2} parameter(s)", procName, methodParams.Count().ToString(), spParamCount.ToString()); 
       throw new Exception(err); 
      } 
      else 
      { 
       context.Database.ExecuteSqlCommand(File.ReadAllText(file), new object[0]); 
      } 
     } 

आनंद लें!

10

यह खराब हालांकि प्रलेखित किया जाना यह अब आप इकाई की रूपरेखा में AlterStoredProcedure, CreateStoredProcedure, DropStoredProcedure, MoveStoredProcedure, RenameStoredProcedure का उपयोग कर कुछ संग्रहित प्रक्रिया में गड़बड़ी कर सकते हैं प्रकट होता है प्रकट होता है 6. मैं उन्हें अभी तक प्रयास नहीं किया है तो अभी तक एक नहीं दे सकता उनका उपयोग कैसे करें इसका उदाहरण।

+0

आपको यहां एक उदाहरण मिल रहा है: http: //www.c-sharpcorner.com/UploadFile/ff2f08/code-first-stored-procedure-entity-framework-6-0/ – Jas

+0

अभी भी खराब दस्तावेज। उदाहरण के लिए धन्यवाद जैस –

8

bbodenmiller's answer पर विस्तार करने के लिए, इकाई की रूपरेखा 6 में, DbMigration class ऐसे AlterStoredProcedure तरीके के रूप में जो कच्चे एसक्यूएल करने के लिए नीचे सभी तरह से छोड़ने के लिए बिना संग्रहित प्रक्रियाओं के संशोधन के लिए अनुमति नहीं है।

यहाँ एक Up() प्रवास विधि है जो एक मौजूदा एसक्यूएल सर्वर संग्रहीत EditItem नामित प्रक्रिया किस प्रकार int, nvarchar(50) के तीन पैरामीटर लेता बदल का एक उदाहरण है, और smallmoney क्रमश:

public partial class MyCustomMigration : DbMigration 
{ 
    public override void Up() 
    { 
     this.AlterStoredProcedure("dbo.EditItem", c => new 
     { 
      ItemID = c.Int(), 
      ItemName = c.String(maxLength:50), 
      ItemCost = c.Decimal(precision: 10, scale: 4, storeType: "smallmoney") 
     }, @" (Stored procedure body SQL goes here) " 
    } 

    //... 
} 

मेरी मशीन पर, इस प्रवास स्क्रिप्ट निम्नलिखित SQL उत्पन्न करता है:

ALTER PROCEDURE [dbo].[EditItem] 
    @ItemID [int], 
    @ItemName [nvarchar](50), 
    @ItemCost [smallmoney] 
AS 
BEGIN 
    (Stored procedure body SQL goes here) 
END 
+0

जबकि मुझे [कार्ल का जवाब] पसंद है (http://stackoverflow.com/a/15171900/947171), यह बहुत अधिक भुगतान के लिए बनाए रखने के लिए बहुत सारे काम की तरह दिखता है। धन्यवाद! –