teisipäev, 28. aprill 2009

Räsi arvutav CLR funktsioon MS SQL SERVERILE

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Security.Cryptography;


public partial class UserDefinedFunctions
{
    [Microsoft.SqlServer.Server.SqlFunction]
    public static byte[] ArvutaRasi(SqlString sona) //STRINGINA ANNAB teksti sisse
    {
        System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
        byte[] data = encoding.GetBytes((string)sona); ;
        byte[] result;
        SHA512 shaM = new SHA512Managed(); //SHA512 või mõni muu
        result = shaM.ComputeHash(data);
        return result; //bitijada tagasi
    }
};
Blogged with the Flock Browser

esmaspäev, 27. aprill 2009

Kuupäevad SQL SERVERIS

Kui vaja võtta DATETIME kuupäevast ära millisekundid

ALTER FUNCTION [dbo].[SEKUNDID_AINULT] ( @kuupaev DATETIME )
RETURNS DATETIME
AS /* Lõikab sisseantud kuupäevast maha millisekundid */
BEGIN
DECLARE @a_data DATETIME
DECLARE @c CHAR(19)
SET @c=CONVERT(CHAR(19),@kuupaev,126 ) --ISO8601 formaat
SET @a_data = CAST(@c AS DATETIME)
RETURN @a_data
END


Kui vaja ainult kuupäeva:

ALTER FUNCTION [dbo].[KUUPAEV_AINULT] ( @kuupaev DATETIME )
RETURNS DATETIME
AS /* Lõikab sisseantud kuupäevast maha tunnid, minutid, sekundid */
BEGIN
DECLARE @a_data DATETIME
DECLARE @c NCHAR(8)
SET @c=CONVERT(NCHAR(8),@kuupaev,112 )
SET @a_data = CAST(@c AS DATETIME)
RETURN @a_data
END

Mõlemad isetehtud funktsioonid töötavad väga hästi erinevate SQL SERVER-i versioonide ja seadistuste korral
Blogged with the Flock Browser

neljapäev, 23. aprill 2009

XML muutujaga pakettmuudatuse (Batch Update) sooritamine

Ühekaupa SQL SERVER-is ridu muuta on SQL SERVER-ile väga piinarikas
kui vaja portsu ridadega andmebaasis midagi teha siis saab kasutada XML muutujat selle asja tegemiseks

Ekraanil mingi asp:TreeNode element, kus saab linnukesega ära märkida, et muuda nüüd selle rea andmeid

Kõigepealt teeb valmis XML muutuja, mille annab andmebaasi protseduuri sisse

using System.Xml;

XmlDocument xdoc = new XmlDocument();
XmlElement el;
el = xdoc.CreateElement("CvNodeElement"); //juurikas
xdoc.AppendChild(el);

foreach (TreeNode no in nod)
{
va = no.Value;
XmlElement childelmt;
XmlAttribute childattr;
//Create child with ID attribute
childelmt = xdoc.CreateElement("Node");
childattr = xdoc.CreateAttribute("ItemId");
childattr.Value = va.ToString();
childelmt.Attributes.Append(childattr);
childattr = xdoc.CreateAttribute("IsPublic");
childattr.Value = no.Checked ? "1" : "0";
childelmt.Attributes.Append(childattr);
el.AppendChild(childelmt);
}

SqlCommandile nüüd XML parameeter külge

komm.Parameters.Add("@doc", SqlDbType.Xml);
komm.Parameters["@doc"].Value = xdoc.InnerXml;


Andmebaasi protseduur

ALTER PROCEDURE [dbo].[CVPublish_Kuido_U]
@doc XML --xml muutuja mis tehakse asp.net-is valmis
AS
BEGIN
SET XACT_ABORT ON
SET NOCOUNT ON
DECLARE @idoc INT
DECLARE @muutused TABLE (Itemid INT, IsPublic BIT)

--lammutame XML-i tabelmuutujaks
EXEC sp_xml_preparedocument @idoc OUTPUT, @doc

INSERT INTO @muutused ([Itemid],[IsPublic])
SELECT Itemid , IsPublic
FROM OPENXML (@idoc, '/CvNodeElement/Node',1)
WITH (ItemId INT, IsPublic BIT)

EXEC sp_xml_removedocument @idoc


--ja nüüd muudame andmebaasis portsul kirjetel
-- CV_CfPersResPatId on tabeli primaarvõti

UPDATE dbo.[CV_CfPersResPat]
SET [CV_CfPersResPat].[IsPublic] = ec.[IsPublic]
FROM dbo.[CV_CfPersResPat] INNER JOIN @muutused AS ec
ON ( CV_CfPersResPat.CV_CfPersResPatId = ec.Itemid
AND [CV_CfPersResPat].[IsPublic] <> ec.[IsPublic] --muudame ainult neil, milel on IsPublic muutunud, hoiab veelgi kokku
)

END


XML-iga muutujate sisseandmist saab kasutada ka siis, kui on vaja protseduurile korraga palju parameetreid sisse annda

Blogged with the Flock Browser

esmaspäev, 20. aprill 2009

Kirjutame ja loeme Windows Serveri Application logisse kasutades LINQ-i

Aeg-ajlat ika viskab vigu ja mõtekas need veateated kuskilegi kirja panna, et hiljem saaks uurida mis süsteemis tegelikult juhtus. Täiesti võimalik on kasutada selleks Windows Serveri EventLog-i

Kõigepealt teeb eelnevalt käsitsi ühe vastava võtme REGEDIT-iga Windows Serverisse

HKEY_LOCAL_MACHINE -> System -> CurrentControlSet -> Services -> EventLog -> Application ja seal paremklõps hiirega Add New Key ja lisab uue võtme MINURAKENDUS

Kui kasutada rakenduse enda vaikimisi veahaldust, ehk Web.Config-is on sees

customErrors mode="RemoteOnly" defaultRedirect="KampError.aspx" redirectMode="ResponseRewrite"

// redirectMode="ResponseRewrite" on .NET Framework 3.5 uuendus

siis KampError.aspx Page_Load meetod võiks välja näha selline

protected void Page_Load(object sender, EventArgs e)
{
this.LiteralViga.Text = "Süsteemis juhtus järgmine tõrge: ";
try
{
Exception ex = Server.GetLastError().GetBaseException();
if (ex != null)
{
this.LiteralViga.Text += "
" + ex.Message.Trim();
// vealogisse kirjutamisel ja ekraanile näitamisel tuleb muidugi jälgida turvalisuse nõudeid
string viga = "SOURCE: " + (ex.Source ?? "") +
"URL: " + (Request.Url == null ? "" : Request.Url.ToString()) +
"URLREFERRER: " + (Request.UrlReferrer == null ? "" : Request.UrlReferrer.ToString()) +
"Crawler: " + (Request.Browser.Crawler == null ? "" : Request.Browser.Crawler.ToString()) +
"USERHOSTNAME: " + (Request.UserHostName == null ? "" : Request.UserHostName.ToString()) +
"USERHOSTADDRESS: " + (Request.UserHostAddress == null ? "" : Request.UserHostAddress.ToString()) +
"USERAGENT: " + (Request.UserAgent == null ? "" : Request.UserAgent.ToString()) +
"QUERYSTRING: " + (Request.QueryString == null ? "" : Request.QueryString.ToString());

//näitame midagi ka ekraanile
this.LabelViga.Text = viga;

if (EventLog.SourceExists("MINURAKENDUS", ".")) //kontrollib, kas on see võti olemas jooksval serveril
{
//logisse kirjutab rohkem võrreldes ekraanile näitamisega
viga += "/nTARGETSITE: " + (ex.TargetSite == null ? "" : ex.TargetSite.ToString()) +
"/nSTACKTRACE: " + (ex.StackTrace == null ? "" : ex.StackTrace) +
"/nINNEREXEPTION: " + (ex.InnerException == null ? "" : ex.InnerException.ToString());
//kirjutame logisse
EventLog.WriteEntry("MINURAKENDUS", this.LiteralViga.Text + "\n" + viga.Replace("
", "\n"), EventLogEntryType.Error);
}
Server.ClearError();
}
}
catch (SystemException ex)
{
this.LabelViga.Text = ex.Message;
}
}


ja kui nüüd vaja lugeda seda MINURAKENDUS vealogi

if (EventLog.SourceExists("MINURAKENDUS"))
{
//siin saab teada selle logi nime, kuhu sisse kirjutame, tavaliselt Application Log
this.literalErrSource.Text = EventLog.LogNameFromSourceName("MINURAKENDUS", ".");
EventLog[] logid = EventLog.GetEventLogs("."); //jooksva serveri vealogid
EventLog kalog = null;

//otsime nime järgi ülesse selle logi nime, kuhu oma veateated sisse kirjutame
foreach (EventLog elog in logid)
{
if (elog.Log == this.literalErrSource.Text)
{
kalog = elog; //leitud
break;
}
}
if (kalog != null) //kui leidsime logi nime
{
//otsime välja MINURAKENDUS teated ja vead
// üks koht kus on mõistlik kasutada LINQ-i

var query = from EventLogEntry el in kalog.Entries
where el.Source == "MINURAKENDUS"
orderby el.TimeGenerated descending
select new
{
Time = el.TimeGenerated,
Message = el.Message,
// Category = el.Category,
EntryType = el.EntryType.ToString(),
// TimeWritten = el.TimeWritten,
UserName = el.UserName
};


//bindime GridView külge ekraanile näitamiseks
this.GridViewLogid.DataSource = query.ToList();
this.GridViewLogid.DataBind();

}
else //kui ei leidnud seda logi nime, kuhu enda veateated kirja paneme näitame lihtsalt logide nimetusi
{
this.GridViewLogid.DataSource = logid;
this.GridViewLogid.DataBind();
}
}


ja edaspidi ei pea enam tõrgete uurimiseks serverisse sisse logima vaid saad vaadata otse rakenduse enda kaudu.

SQL SERVER Agent kuupäeva funktsioon

Kui lugeda andmeid SQL SERVER Agent tabelitest, MSDB andmebaasist siis kuupäeva ja kellaaeg on antud seal INT väärtuste kujul, et nüüd nendest asjadest mõistlikku kuupäeva saada võib kasutada järgmist funktsiooni mis genereerib kellaaja lähtudes tabeli date ja time numbritest


CREATE FUNCTION [dbo].[SQLSERVERAGENTDATETIME_KUIDO] (@agentdate INT, @agenttime INT)
RETURNS DATETIME
AS
BEGIN
DECLARE @Result DATETIME
DECLARE @date DATETIME, @year INT, @month INT, @day INT, @datestr NVARCHAR(40)
,@hour INT, @min INT, @sec INT, @timestr NVARCHAR(40)

SET @year = (@agentdate / 10000)
SET @month = (@agentdate - (@year * 10000)) / 100
SET @day = (@agentdate - (@year * 10000) - (@month * 100))

IF @agentdate = 0
RETURN @Result --võib rõõmsalt ka NULL-i tagasi anda, kui kuupäeva pole

SET @datestr = CONVERT(NVARCHAR(4), @year) +
RIGHT('0'+CONVERT(NVARCHAR(2), @month),2) +
RIGHT('0'+CONVERT(NVARCHAR(2), @day),2)

SET @hour = (@agenttime / 10000)
SET @min = (@agenttime - (@hour * 10000)) / 100
SET @sec = (@agenttime - (@hour * 10000) - (@min * 100))
SET @timestr = RIGHT('00'+CONVERT(NVARCHAR(2), @hour),2) + N':' +
RIGHT('00'+CONVERT(NVARCHAR(2), @min),2) + N':' +
RIGHT('00'+CONVERT(NVARCHAR(2), @sec),2)
SET @Result = CONVERT(DATETIME, @datestr+' '+@timestr,112)
RETURN @Result

END


Kasutada niimoodi, kui vaja teada millal automaatseid töid käivitati

SELECT [message], run_status, sql_severity, step_id
,[dbo].[SQLSERVERAGENTDATETIME_KUIDO](run_date, run_time) AS RUN_TIME FROM MSDB.dbo.sysjobhistory

Veebilehe laadimisaja suurendamine

Kui juhtub nii, et veebilehe tegemiseks kulub tavalisest rohkem aega ja pillub lõpuks veateadet
System.Web.HttpException Request timed out

Sel juhul kui miski muu enam ei aita tuleb seda veebilehe tegemise aega suuendada

Server.ScriptTimeout = 600; // sätib aja 5 minuti peale

Blogged with the Flock Browser

neljapäev, 16. aprill 2009

System.Net.Mail MailMessage.BodyEncoding läheb hieroglüüfe täis

Saadad ülalminitud asjaga e-posti ja kui võtad Outlookiga kirja lahti ja Vasta tuleb pilt selline

asja saab kord kui Unicode kodeering asendada ANSI 1252-ga

//email.BodyEncoding = Encoding.Unicode; //see paneb Outlooki hieroglüüfid sisse
email.BodyEncoding = System.Text.Encoding.GetEncoding(1252);
email.IsBodyHtml = false;



Blogged with the Flock Browser

teisipäev, 7. aprill 2009

SQLConnectionPooli tühjendamine

Juhul, näiteks, kui muudame SQL SERVER Logini parameetreid, näiteks Default Language siis võib juhtuda, et saame veateate
Resetting the connection results in a different state than the initial login. The login fails. Login failed for user 'MINE_KUULE'. A severe error occurred on the current command. The results, if any, should be discarded.

Põhjuseks on SQL Connection Pooli(basseini) olemasolu, mis peab meeles mis sätetega SQL SERVERI login basseini tuli ja kui vahepeal loginit muuta siis basseinis jääb see ju uuendamata. Kui nüüd teha uus päring andmebaasi siis Connection Pooli ja SQLSERVERI login ei lange enam parameetrite poolest kokku.
Lahti saab asjast nii, et tuleb bassein peale SQL SERVER logini muutmist tühjendada

Näiteks muudame SQL SERVER logini keelt süsteemse protseduuriga

EXECUTE sp_defaultlanguage @loginame = @login_name , @language = @lang_name

siis tema kasutamine koos pooli tühjendmisega näeb välja nii, ( DBO.SET_WORKER_LANGUAGE_KUIDO_U on üks enda tehtud salvestatud protseduur mille
sees ka seda sp_defaultlanguage kasutatakse)

using System.Data;
using System.Data.SqlClient;

using (SqlConnection Connection = new SqlConnection(Configuration.ConnectionString))
{
SqlCommand Command = new SqlCommand("DBO.SET_WORKER_LANGUAGE_KUIDO_U",Connection);
Command.CommandType=CommandType.StoredProcedure;
Command.Parameters.AddWithValue("@login_name", username.Trim());
Command.Parameters.AddWithValue("@lang_name", language.Trim());
Connection.Open();
Command.ExecuteNonQuery();
Connection.Close();
//basseini tühjendamine ainult selle ühenduse logini jaoks
SqlConnection.ClearPool(Connection);
// SqlConnection.ClearAllPools(); //kogu bassein tühjaks
}

Blogged with
the Flock Browser