דילוג לתוכן
  • דף הבית
  • קטגוריות
  • פוסטים אחרונים
  • משתמשים
  • חיפוש
  • חוקי הפורום
כיווץ
תחומים

תחומים - פורום חרדי מקצועי

💡 רוצה לזכור קריאת שמע בזמן? לחץ כאן!
  1. דף הבית
  2. תכנות
  3. סקריפט ליצירה אוטומטית של מחלקות C# מבסיס נתונים ב-SQL Server

סקריפט ליצירה אוטומטית של מחלקות C# מבסיס נתונים ב-SQL Server

מתוזמן נעוץ נעול הועבר תכנות
6 פוסטים 4 כותבים 240 צפיות
  • מהישן לחדש
  • מהחדש לישן
  • הכי הרבה הצבעות
התחברו כדי לפרסם תגובה
נושא זה נמחק. רק משתמשים עם הרשאות מתאימות יוכלו לצפות בו.
  • OdedDvirO מנותק
    OdedDvirO מנותק
    OdedDvir
    כתב ב נערך לאחרונה על ידי
    #1

    טוב, אז אני מניח שהכותרת די ברורה:
    כידוע, לפי הספר, כל טבלה ב-SQL קלאסי אמורה לייצג יישות (Entity), שבד"כ מיוצגת על ידי מחלקה (Class) תואמת בתוכנה.
    כל פעם שאני בא להמיר איזה פרוייקט מאקסס ל-C# אני נתקל בעבודה הסיזיפית הזו.

    חיפשתי פיתרון שיתן לי ליצור בקלות את כל המודלים של הנתונים מתוך הגדרות הטבלאות.

    יש איזו דרך מתוסבכת לעשות זאת על ידי EntityFramework, אבל עד עכשיו הייתי משתמש באתר CodVerter ליצירה של מחלקה על ידי הכנסה של הגדרות הסקריפט SQL שיוצר אותה,

    ז"א אם אני מכניס את הסקריפט הבא:

    CREATE TABLE [dbo].[Sender] (
        [SenderID]   INT           NOT NULL,
        [SenderName] NVARCHAR (50) NOT NULL
    );
    

    אני מקבל בתמורה:

    public class Sender
    {
    	public int SenderID {get;set;}
    	public string SenderName {get;set;}
    }
    

    וזה כמובן נחמד כשמדובר בכמה טבלאות בודדות, אבל כשצריך להעביר עשרות טבלאות, זה מאוד לא נוח.

    אבל היום גיליתי סקריפט נהדר ב-CodeProject, שיוצר בבת אחת את כל הקלאסים עבור כל הטבלאות ב-DB, וחסך לי כאב ראש גדול.

    אז הנה הוא לפניכם (בתיקון שגיאה קטנה שהיתה במקור): פשוט לפתוח את בסיס הנתונים ב-SSMS, להדביק את הסקריפט הבא, להריץ, לקבל את כל הקלאסים על מגש של כסף, ולהגיש חם עם כוס נס-קפה:

    SET NOCOUNT ON;  
      
    DECLARE @table_name NVARCHAR(250), @message VARCHAR(80);  
      
    DECLARE table_cursor CURSOR FOR   
    select distinct tab.name as table_name
    from sys.tables as tab
        inner join sys.columns as col on tab.object_id = col.object_id
        left join sys.types as t on col.user_type_id = t.user_type_id
    order by table_name;  
      
    OPEN table_cursor  
      
    FETCH NEXT FROM table_cursor   
    INTO @table_name  
      
    WHILE @@FETCH_STATUS = 0  
    BEGIN  
        PRINT ' '  
        --SELECT @message = 'Table Name: ' +   
        --    @table_name  
      
        --PRINT @message  
      
        --declare @TableName sysname = 'TableName'
        declare @Result varchar(max) = 'public class ' + @table_name + '
    {'
    
        select @Result = @Result + '
        public ' + ColumnType + NullableSign + ' ' + ColumnName + ' { get; set; }'
        from
        (
        select 
        replace(col.name, ' ', '_') ColumnName,
        column_id ColumnId,
        case typ.name 
        when 'bigint' then 'long'
        when 'binary' then 'byte[]'
        when 'bit' then 'bool'
        when 'char' then 'string'
        when 'date' then 'DateTime'
        when 'datetime' then 'DateTime'
        when 'datetime2' then 'DateTime'
        when 'datetimeoffset' then 'DateTimeOffset'
        when 'decimal' then 'decimal'
        when 'float' then 'float'
        when 'image' then 'byte[]'
        when 'int' then 'int'
        when 'money' then 'decimal'
        when 'nchar' then 'char'
        when 'ntext' then 'string'
        when 'numeric' then 'decimal'
        when 'nvarchar' then 'string'
        when 'real' then 'double'
        when 'smalldatetime' then 'DateTime'
        when 'smallint' then 'short'
        when 'smallmoney' then 'decimal'
        when 'text' then 'string'
        when 'time' then 'TimeSpan'
        when 'timestamp' then 'DateTime'
        when 'tinyint' then 'byte'
        when 'uniqueidentifier' then 'Guid'
        when 'varbinary' then 'byte[]'
        when 'varchar' then 'string'
        else 'UNKNOWN_' + typ.name
        end ColumnType,
        case 
        when col.is_nullable = 1 and typ.name in ('bigint', 'bit', 'date', 
        'datetime', 'datetime2', 'datetimeoffset', 'decimal', 'float', 'int', 
        'money', 'numeric', 'real', 'smalldatetime', 'smallint', 'smallmoney', 
        'time', 'tinyint', 'uniqueidentifier') 
        then '?' 
        else '' 
        end NullableSign
        from sys.columns col
        join sys.types typ on
        col.system_type_id = typ.system_type_id AND col.user_type_id = typ.user_type_id
        where object_id = object_id(@table_name)
        ) t
        order by ColumnId
    
        set @Result = @Result  + '
    }'
    
        print @Result
      
        FETCH NEXT FROM table_cursor   
        INTO @table_name  
    END   
    CLOSE table_cursor;  
    DEALLOCATE table_cursor;  
    

    נ.ב. יתכן ואני מגלה את אמריקה ויש דרך יותר קלה\סטנדרטית, אם כן - אשמח לשמוע.

    חגיח רפאלר dovidD 3 תגובות תגובה אחרונה
    4
    • חגיח מנותק
      חגיח מנותק
      חגי
      השיב לOdedDvir ב נערך לאחרונה על ידי
      #2

      @OdedDvir
      אתה יכול לגרום לentity framework ליצור את המחלקות הללו בשבילך ב-.net הרגיל (לא core), וזה גם מגיע עם עורך ויזואלי לקשרים בין טבלאות.
      בcore אין את כל הדברים השווים האלה בגלל שזאת הקידמה, כך מסתבר...

      dovidD תגובה 1 תגובה אחרונה
      2
      • רפאלר מנותק
        רפאלר מנותק
        רפאל
        השיב לOdedDvir ב נערך לאחרונה על ידי רפאל
        #3

        הדרך הרשמית לבצע זאת בEntity Framework Core היא שימוש בפקודה dotnet ef dbcontext scaffold, אשר תיצור את הDbContext ואת הEntities בצורה אוטומטית, אחת מהמעלות הבולטות של השימוש בפקודה היא השינוי של שמות המחלקות והProperties כך שיתאימו למוסכמות של C# (ניתן לבטל את הפיצר באמצעות הפרמטר use-database-names--) כמו כן באמצעות הכלי ניתן להגדיר דברים רבים נוספים הקשורים ליצירה של המחלקות.

        דוגמא בסיסית (שימוש בlocaldb):

        dotnet ef dbcontext scaffold "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=DatabaseName" Microsoft.EntityFrameworkCore.SqlServer
        

        דוגמא נרחבת:

        dotnet ef dbcontext scaffold "Server=ServerName; Database=DatabaseName; User Id=UserId; Password=Password" Microsoft.EntityFrameworkCore.SqlServer   --context=DbContext --context-dir  DbDir --data-annotations --output-dir DbDir/Entities
        

        לשימוש בכלי מומלץ להתקינו גלובלית:

        dotnet tool install --global dotnet-ef
        
        תגובה 1 תגובה אחרונה
        3
        • dovidD מנותק
          dovidD מנותק
          dovid ניהול
          השיב לחגי ב נערך לאחרונה על ידי
          #4

          @חגי הוא הזכיר זאת, רק תיאר את זה כדרך מסובכת.
          זה אכן לא מסובך, זה תבנית T4 של ייצור קוד, אבל זה אכן הרבה יותר קל הקוד שהובא פה. אבל לשינויים תכופים הוא פחות נח (בT4 זה בלחיצת כפתור ימני וריענון).

          מנטור אישי למתכנתים (ולא רק) – להתקדם לשלב הבא!

          בכל נושא אפשר ליצור קשר dovid@tchumim.com

          OdedDvirO תגובה 1 תגובה אחרונה
          3
          • dovidD מנותק
            dovidD מנותק
            dovid ניהול
            השיב לOdedDvir ב נערך לאחרונה על ידי
            #5

            @OdedDvir אמר בסקריפט ליצירה אוטומטית של מחלקות C# מבסיס נתונים ב-SQL Server:

            כידוע, לפי הספר, כל טבלה ב-SQL קלאסי אמורה לייצג יישות (Entity), שבד"כ מיוצגת על ידי מחלקה

            זה לא בהכרח. זה נכון אם אתה משתמש בORM או שאתה חובב טיפוסיות קשוחה.

            מנטור אישי למתכנתים (ולא רק) – להתקדם לשלב הבא!

            בכל נושא אפשר ליצור קשר dovid@tchumim.com

            תגובה 1 תגובה אחרונה
            2
            • OdedDvirO מנותק
              OdedDvirO מנותק
              OdedDvir
              השיב לdovid ב נערך לאחרונה על ידי
              #6

              תודה @רפאל על הדוגמא המפורטת, כהרגלך הטוב!

              @dovid @חגי, אם כוונתכם למקור שציינתי, אני משתמש ב-Core, והתקנת התבנית DAO.Entity בכלל לא הופיעה לי בתור אופציה. (שמא זה בגלל התמיכה רק ב Framework הישן) זה מה שסיבך עבורי את העניין...

              @dovid אמר בסקריפט ליצירה אוטומטית של מחלקות C# מבסיס נתונים ב-SQL Server:

              זה נכון אם אתה משתמש בORM או שאתה חובב טיפוסיות קשוחה.

              מודה באשמה...

              תגובה 1 תגובה אחרונה
              3

              בא תתחבר לדף היומי!
              • התחברות

              • אין לך חשבון עדיין? הרשמה

              • התחברו או הירשמו כדי לחפש.
              • פוסט ראשון
                פוסט אחרון
              0
              • דף הבית
              • קטגוריות
              • פוסטים אחרונים
              • משתמשים
              • חיפוש
              • חוקי הפורום