kolmapäev, 28. oktoober 2009

Ära näita sirviku JavaScriptile küpsiseid

kui sul seda vaja ei ole, ehk lisa web.config faili rida httpOnlyCookies="true"
saad murdskriptimise vastu võidelda, sirviku Javascript ei pääse enam küpsisele ligi (sõltub sirvikust ja selle versioonist)
ja kui vaja ka et küpsised läheksid läbi SSL-i võid panna ka selle jupi juurde
requireSSL="true"


reede, 23. oktoober 2009

XML andmete näitamine TreeView ja XmlDataSourcega

Andmebaasis on XML väli kuhu paneb sisse igasugu andmeid, peamiselt logimisinfot mille jaoks iga kord tabelisse eraldi tulpa teha ei viitsi. XML andmete stuktuur kuidas kunagi
mõnel rohkem
mõnel vähem
ja tulevikus võib vajadusel juurde lisada.

Ekraanil hierarhiliste andmete näitamiseks sobib hästi TreeView nimeline control, XML andmed salvestab XmlDataSourceTähele peab panema, et XmlDataSource on EnableCaching vaikimisi True, kuna vaja andmebaasist dünaamiliselt iga kord uusi andmeid näidata tuleb
EnableCaching="false" seada

Vaikmisi TreeView seab andmed XML elementde külhge, et ekraanil näitab ainult
Options, AcceptedUser ja RELATED_CONTRACT teksti nii nagu XML andmete tippude nimed on, kuna see mis andmebaasi XML väljast tuleb võib igakord erinev olla siis
ontreenodedatabound="TreeViewExtraInfo_TreeNodeDataBound" eventis tuleb natuke käsitsitööd teha, näiteks nii:

protected void TreeViewExtraInfo_TreeNodeDataBound(object sender, TreeNodeEventArgs e)
{
try
{
System.Xml.XmlElement cdf = (System.Xml.XmlElement)e.Node.DataItem;

if (cdf.Name == "Options") //juurelement
{
e.Node.Text = Resources.Resource.ExtraInfo;
}
else
{
if (cdf.InnerXml != "")
{
try //kui ta sellist node nimetust ei leia resursi tekstidest, võtame NODE enda nime
{
e.Node.Text = HttpContext.GetGlobalResourceObject("Resource", cdf.Name).ToString()+ " " + cdf.InnerText;
}
catch (SystemException ex)
{
e.Node.Text = cdf.Name + " " + cdf.InnerText;
}
}
}
if (cdf.HasAttributes) //kui on atribuute siis lisame elemendile ühe alamtipu
{
for (int i = 0; i < cdf.Attributes.Count; i++)
{
TreeNode db;
try
{
//kas ressursi tekstides on tipu elemendi kirjeldus olemas
db = new TreeNode(HttpContext.GetGlobalResourceObject("Resource", cdf.Attributes[i].Name).ToString() + " " + cdf.Attributes[i].Value);
}
catch (SystemException ex)
{
db = new TreeNode(cdf.Attributes[i].Name + " " + cdf.Attributes[i].Value);
}
e.Node.ChildNodes.Add(db);
}
}
}
catch (SystemException ex)
{
this.CustomValidator1.ErrorMessage = ex.Message;
this.CustomValidator1.IsValid = false;
}
}

Ekraanile aga paistab:


AcceptedUseri all on atribuutidest tehtud lisatipud

Andmete külgepanemine käib XmlDataSourceExtraInfo.Data property kaudu
this.XmlDataSourceExtraInfo.Data = this.ApplicationOptions(this.application_id);
this.TreeViewExtraInfo.DataBind();

siin this.ApplicationOptions(this.application_id) tagastab XML stringi mille andmebaasi XML väljast loen

public string ApplicationOptions(int applicationId)
{
string retu = "";
using (SqlConnection konn = new SqlConnection(Configuration.ConnectionString))
{

SqlCommand komm = new SqlCommand("SELECT [dbo].[APPLICATION_OPTIONS_KUIDO_S](" + applicationId.ToString() + ")", konn);
komm.CommandType = CommandType.Text;
konn.Open();
Object ret = komm.ExecuteScalar();
if (!ret.Equals(DBNull.Value))
{
retu = ret.ToString();
}
konn.Close();
}
return retu;
}

teisipäev, 20. oktoober 2009

GridView tulba peitmine andmebaasi välja põhjal

Kui vaja teha mingi PIVOT päring andmebaasist või üldse juhtudel kus andmebaasist võib iga kord erinevate tulpade arvuga Tabular Data Stream (TDS) vastu tulla ning vaja seda ekraanil kuvada nii, et mõnda tulpa ei näitaks siis üks asja lahendus on GridView kasutamine AutoGenerateColumns="True" seadistusega.

Kuna GridView sisse saab teha igasugu tüüpi tulpasid siis põhimõte on see, et kontrollime, kas on teatud tüüpi tulp. Näiteks kontrollime, kas on BoundField tüüpi tulp ja kui on siis kas DataField langeb otsitavaga kokku.

///
/// tagastab GridView asp:BoundField tüüpi tulba indeksi DataField nime põhjal
///

///
/// fieldName on DataFieldi väli mida otsida
///
public int GetGridColumnIndex(GridView grd, string fieldName)
{
for (int i = 0; i < grd.Columns.Count; i++)
{
DataControlField field = grd.Columns[i];
//üritame pöörata BoundField-iks
BoundField bfield = field as BoundField;
//kui on BoundField ja DataField langeb ka kokku tagastame tulba indeksi
if (bfield != null && bfield.DataField.ToUpper() == fieldName.ToUpper())
{
return i;
}
}
return -1;
}


Tulba peitmine, PEIDATULP on see TDS tulp mida näidata ei taha

//leiame selle tulba numbri, mida ei tohi näidata
int tlnr = GetGridColumnIndex(this.GridViewKeeled, "PEIDATULP");
if (tlnr != -1)
{
this.GridViewKeeled.Columns[tlnr].Visible = false;
}

kolmapäev, 14. oktoober 2009

BULK INSERT tekstifailist CLR-i kasutades

Sai kogemata SQLSERVER 2008 Web Edition maha müüdud ja siis avastatud, et Integration Services selle versiooni sees ei olegi. Kokkuvõttes tuleb asjad ise teha ja loeme nüüd BULK INSERT käsuga otse tekstifailist:


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 HansaImport(SqlString fail, SqlString kataloog, SqlString sihttabel, SqlInt32 kustutafail)
{
//teeme sisendparameetrite kontrolli ja lõikame lõpud maha
string siht = Convert.ToString(sihttabel);
siht=siht.Substring(0, (siht.Length > 30 ? 30 : siht.Length));
string kat = Convert.ToString(kataloog);

kat = kat.Substring(0, (kat.Length > 30 ? 30 : kat.Length));
string fai = Convert.ToString(fail);
fai = fai.Substring(0, (fai.Length > 20 ? 20 : fai.Length));
string impafail = kat + fai;
if (System.IO.File.Exists(impafail))
{
using (SqlConnection konn = new SqlConnection("Context connection=true"))
{
SqlCommand komm = new SqlCommand("TRUNCATE TABLE " + siht + "; BULK INSERT " + siht + " FROM '" + impafail + "' WITH (FIELDTERMINATOR ='\t',ROWTERMINATOR ='\n', BATCHSIZE = 10000)", konn);
konn.Open();
komm.ExecuteNonQuery();
konn.Close();
if (kustutafail == 1)
{
System.IO.File.Delete(impafail);
}
}
}
else
{
throw new SystemException("CLR Error !! Missing file: " + fai + " in directory: " + kat);
}
}
}


Kui nüüd värk käivitada Management Studio alt siis kõik OK aga kui panna jooksma kui andmebaasi töö tuleb selline viga

Bulk load data conversion error (type mismatch or invalid character for the specified codepage) for row

Tekstifailis on kuupäev kujul 23.10.2009

Et asi andmebaasi tööna jooksma saada anname temale kuupäeva formaadi ette
SET DATEFORMAT DMY
EXECUTE [dbo].[HansaImport]
@fail='arved.txt'
,@kataloog='D:\HANSA_IMPORT\'
,@sihttabel='[dbo].[HANSA_ARVED_TEMP]'
,@kustutafail=0

SQL SERVER Agent kasutab SQL SERVERi enda kuupäeva seadeid asjadest aru saamiseks

reede, 9. oktoober 2009

Andmebaasi tööde ülevaade

Selleks, et mingi SQL SERVER Agent-i töö käiks peab
1. Töö ise olema lubatud
2. Töö enda plaanur olema lubatud

Kuna mõnikord unustad selle märkeruudu "Enabled" peale sättida siis abiks SP mis teeb ülevaate SQL Agenti andmebaasi töödest.

ENABLED väli näitab kas töö on peatatud
SCHEDULE_ENABLED väli näitab kas töö plaanur on peatatud

[dbo].[SQLSERVERAGENTDATETIME_KUIDO] funktsiooni ma olen kirjeldanud
varasemalt siin http://kuidoveeb.blogspot.com/2009/04/sql-server-agent-kuupaeva-funktsioon.html

Parameeter @job_names võimaldab filtreerida töö nime alguse järgi

-- =============================================
-- Description: Andmebaasi tööde nimekiri
-- =============================================
CREATE PROCEDURE [dbo].[WINTIME_JOBS_KUIDO_S]
@job_names NVARCHAR(128)=N'MINUTOOD'
WITH EXECUTE AS 'DBO' --käivitame teatud kasutaja õigustes kuna pole mõtet and igaühele otse tabelitele juurdepääsu
AS
BEGIN
SET NOCOUNT ON
DECLARE @err INT
IF RIGHT(@job_names,1) <> '%'
SET @job_names=@job_names+'%'
--OTSIME KÕIGEPEALT SOBIVAD TÖÖD VÄLJA (filter nime alguse järgi)
DECLARE @tood TABLE (job_id UNIQUEIDENTIFIER PRIMARY KEY, job_name NVARCHAR(128) COLLATE DATABASE_DEFAULT, enabled TINYINT,
job_owner NVARCHAR(128) COLLATE DATABASE_DEFAULT NULL )
INSERT INTO @tood (job_id, job_name, [enabled] , job_owner)
SELECT sj.JOB_ID, sj.NAME, sj.[enabled],su.name FROM [msdb]..sysjobs sj
LEFT JOIN msdb..[SYSUSERS] su ON (sj.owner_sid = su.sid )
WHERE sj.name LIKE @job_names
--TEEME ÜLEVAATE
SELECT ISNULL(b.job_owner,'') AS job_owner, b.job_name, b.job_id, b.[enabled]
,[dbo].[SQLSERVERAGENTDATETIME_KUIDO](c.next_run_date,c.next_run_time) AS NEXT_RUN_TIME
,a.step_name, a.subsystem, a.command, a.database_name
,a.step_id, a.step_name, c.schedule_enabled
,Hist.[MESSAGE] AS LAST_RUN_MESSAGE, Hist.LAST_RUN_TIME
,Hist.[RUN_DURATION] AS LAST_RUN_DURATION, Hist.RUN_STATUS AS LAST_RUN_STATUS
FROM msdb..sysjobsteps a
INNER JOIN @tood b ON ( a.job_id =b.job_id )
INNER JOIN (SELECT sc.job_id , sc.next_run_time, sc.next_run_date, ssc.[enabled] AS schedule_enabled
FROM msdb..sysjobschedules sc --uurib ka schedule on enabled
INNER JOIN [msdb]..[sysschedules] ssc ON (sc.[schedule_id] = ssc.[schedule_id])
WHERE EXISTS (SELECT job_id FROM @tood Tli WHERE Tli.job_id = sc.job_id )
) c ON (a.job_id = c.job_id)
INNER JOIN
(
SELECT DISTINCT J1.JOB_ID, J1.[MESSAGE],
[dbo].[SQLSERVERAGENTDATETIME_KUIDO](J1.RUN_DATE,J1.RUN_TIME) AS LAST_RUN_TIME,
J1.RUN_STATUS, J1.RUN_DURATION
FROM msdb.dbo.sysjobhistory J1 WHERE J1.step_id=0
AND job_id IN (SELECT job_id FROM @tood Tli )
AND ( [dbo].[SQLSERVERAGENTDATETIME_KUIDO](J1.RUN_DATE,J1.RUN_TIME) =
( SELECT MAX([dbo].[SQLSERVERAGENTDATETIME_KUIDO](J2.RUN_DATE,J2.RUN_TIME) )
FROM msdb.dbo.sysjobhistory J2 WHERE J1.[job_id] = J2.JOB_ID AND J2.step_id=0) )
) Hist ON (a.job_id = Hist.JOB_ID )
ORDER BY B.JOB_NAME
/*
LAST_RUN_STATUS
0 Failed
1 Succeeded
2 Retry (step only)
3 Canceled
4 In-progress message
5 Unknown
*/
END

neljapäev, 1. oktoober 2009

XML välja sisu ilusaks ajamine peale sql:variable-ga mudimist

Selline juhtum, kui on vaja SQL SERVER-i XML muutujat vahepeal muuta no näiteks
DECLARE @aop XML, @lep INT, @relcon NVARCHAR(2000)

SET @relcon=''+CAST(@contractId AS NVARCHAR(20))+''

SET @lep = @aop.value('/RELATED_CONTRACT[1]', 'INT')
IF @lep IS NULL --KUI RELATED_CONTRACT on puudu, lisame vastava NODE
SET @aop.modify('insert text{sql:variable("@relcon")} as last into (/Options)[1]')

kui nüüd SQL SERVER manageriga seda @aop sisu vaadata on seal '<' asemel
mis ei ole üldsegi ilus, et see asi korda saada tuleb stringitöötlust teha, XML muutuja pöörata NVARCHAR(MAX), muuta ära ja pöörata XML-iks tagasi


Kui tahad XML välja RAISERRORIGA ekraanile lasta, siis tuleb samuti stringitöötlust teha

SET @relcon = REPLACE(CAST(@aop AS NVARCHAR(4000)),'<','_')
RAISERROR('XML info %s',16,1,@relcon)

ASP.NET tõlgendab ju '<' algavaid asju kui HTML-i elemente mis tegelikult ongi õige