Wykład 12 Programowanie serwera MS SQL 2005 w C# Budowa procedur składowanych w C# Budowa funkcji składowanych w C# Wykorzystanie funkcji składowanych w C# po stronie klienta Tworzenie typów definiowanych przez użytkownika w C# 1
Budowa procedur składowanych w C# Kod zarządzany, który ma rezydować na serwerze SQL jako np. procedura składowana czy funkcja pamiętana (również widok, wyzwalacz, nowy typ danych) jest statyczną metodą klasy. Taka metoda implementująca procedurę pamiętaną jest opatrzona atrybutem Microsoft.SqlServer.Server.SqlProcedure Umożliwia on utworzenie dla tej metody procedury wykonywalnej w CLR. Serwer SQL 2005 domyślnie nie pozwala na wykonywanie kodu CLR. Należy w tym celu zmienić jego konfigurację. Po połączeniu z serwerem jeśli posiadamy uprawnienia administratora wykonujemy polecenie: a następnie polecenie: sp_configure 'clr enable', 1 reconfigure 2
W środowisku Visual Studio możemy w celu zaprogramowania procedury pamiętanej tworzymy specjalny rodzaj projektu SQL Server Project (slajd 4). Następnie należy wskazać bazę danych na wybranym serwerze SQL (slajd 5). System tworzy szablon projektu, który uzupełniono przykładowo definicją procedury pamiętanej o nazwie TestProcedure z jednym parametrem wyjściowym outtytul. using System; using System.Data; using System.Data.SqlClient; using System.Data.SqlTypes; using Microsoft.SqlServer.Server; public partial class StoredProcedures [Microsoft.SqlServer.Server.SqlProcedure] public static void TestProcedure(out SqlString outtytul) // Put your code here outtytul = "Procedura składowana"; ; 3
4
5
Przebudowa projektu utworzy plik dll, który po uruchomieniu w trybie debugowania zostanie umieszczony na serwerze w wybranej bazie danych. 6
7
Po dodaniu do nowego projektu funkcji definiowanej przez użytkownika (slajd 9) wybranie opcji User-Defined Function system wygeneruje pusty szablon definicji funkcji pamiętanej w C#. Po uzupełnieniu szablonu definicją funkcji pamiętanej (slajd 9) wystarczy przebudować projekt, aby utworzyć plik dll, a następnie wykonać go w trybie debugger'a, co spowoduje zarejestrowanie nowej funkcji w bazie danych (slajd 10). 8
9
using System; using System.Text; using System.Data; using System.Data.SqlClient; using System.Data.SqlTypes; using Microsoft.SqlServer.Server; public partial class UserDefinedFunctions [Microsoft.SqlServer.Server.SqlFunction] public static SqlString Function1(SqlString a1, SqlString a2, SqlString t, SqlString rw) // Put your code here StringBuilder sb = new StringBuilder(); sb.appendformat("0, 1, 2, 3", a1, a2, t, rw); return new SqlString(sb.ToString()); ; 10
11
Przykład ilustruje wykorzystanie funkcji pamiętanej napisanej w C# w aplikacji klienckiej: using System; using System.Collections.Generic; using System.Text; using System.Data; using System.Data.Common; using System.Data.SqlClient; namespace TestFunkcji class Program static void Main(string[] args) SqlConnectionStringBuilder connbldr = new SqlConnectionStringBuilder(); connbldr.datasource = "TEJOT"; connbldr.initialcatalog = "MS_biblioteka"; connbldr.integratedsecurity = true; connbldr.connecttimeout = 30; SqlConnection conn = new 12
SqlConnection(connBldr.ConnectionString); //conn.open(); SqlCommand polecenie = new SqlCommand(); polecenie.commandtext = "select dbo.function1(rtrim(autor_1), Rtrim(Autor_2), Rtrim(Tytul), Rok_wydania) from Ksiegozbior"; conn.open(); polecenie.connection = conn; SqlDataReader dr = polecenie.executereader(commandbehavior.closeconnection); bool następny = true; while (następny) while (dr.read()) Console.WriteLine(dr.GetString(0)); następny = dr.nextresult(); dr.close(); conn.close(); Console.ReadKey(); 13
14
Tworzenie typów definiowanych przez użytkownika w C# using System; using System.Data; using System.Data.SqlClient; using System.Data.SqlTypes; using Microsoft.SqlServer.Server; using System.Text; [Serializable] [Microsoft.SqlServer.Server.SqlUserDefinedType(Format.Native)] public struct Punkt3D : INullable private bool isnull; private int x, y, z; public override string ToString() if (IsNull) return "NULL"; else StringBuilder sb = new StringBuilder(); sb.appendformat("0, 1, 2", x, y, z); return sb.tostring(); 15
public bool IsNull get return isnull; public static Punkt3D Null get Punkt3D h = new Punkt3D(); h.isnull = true; return h; 16
[SqlMethod(OnNullCall = false)] public static Punkt3D Parse(SqlString s) Punkt3D u = new Punkt3D(); string rawvalue = s.value; try string[] vals = rawvalue.split(','); u.x = Int32.Parse(vals[0]); u.y = Int32.Parse(vals[1]); u.z = Int32.Parse(vals[2]); catch(exception e) throw new ArgumentException("Format niewłaściwy", e); return u; [SqlMethod(OnNullCall = false)] public Double OdległośćOdPunktu(Punkt3D origin) return Math.Sqrt(Math.Pow(x - origin.x, 2.0) + Math.Pow(y - origin.y, 2.0) + Math.Pow(z - origin.z, 2.0)); 17
public int X get return x; set x = value; public int Y get return y; set y = value; public int Z get return z; set z = value; I wykorzystanie tego UDT w bazie danych na serwerze. Utworzono w bazie MS_biblioteka nową tabelę Punkty 18
19
20