Defensive Database Programming ingyenes könyv
Saturday, May 15th, 2010Érdekesnek ígérkezik, ingyenes, letölthető könyv.
Érdekesnek ígérkezik, ingyenes, letölthető könyv.
Az alábbi kérdezték tőlem pár perce:
SELECT [text] FROM [table1] WHERE [text] like '%rekes%'
A rekesz szót nem találja meg, ha magyar a collation az oszlopon. Ez természetes, a kettős betűket ezzel a logikával kezeli a szerver, azaz egy betűnek tekinti őket. A where-be kell egy collation cast, mondjuk latin1-re, amiben nincsenek kettős betűk. Mondjuk ezután nem fog indexet használni a szerver, de a kezdő % miatt eleve nem használva.
Az alábbi példában az egyikkel collationnel megtalálja, másikkal nem.
SELECT [text] FROM [table1] WHERE [text] like '%rekes%' -- collate Hungarian_CI_AS collate Latin1_General_CI_AS
Lehet csinálni indexelt, számított oszlopot is más collationnel, és arra szűrni, az gyorsabb lesz.
Jó ez a VS 2010. Belefutottam egy problémába, amiben a Parallel stack segítsége jól jött.

Amint a képen látható az egyik szál bejár egy Dictionary-t serializálás miatt, miközben a másik beleenyúl, ettől aztán elszakad a cérna az iterátornál. Látható a képen, hogy két SaveSettings egyszerre fut, de csak az egyik seralizál, a másik, a jobbról látható vár, mert raktam be lockot.
Igen, ám, de rossz helyre! A kollekciót engedem módosítani (this[string].set), mert az a lockoláson kívül esik. Azaz a probléma a rosszul megválasztott zárolási szint (lock scope). Egy metódushívással kijjebb kell rakni, az indexerbe.
A VS coverage-e ezt mutatja, hogy ez a sor csak részben van lefedve:
return (GetSourceItem(step) - this[step - 1]) * e + this[step - 1];
Nincs benne && vagy ||, akkor triviális lenne. Én már tudom a választ. :)
Update: alul, kommentben ott a megoldás.
Az RC óta elfelejtettem, hát leírom magamnak.
Nincs bennük Windows Auth, így nem megy a debugging se. Ref. Nagy cumi ez. Ha valaki tud rá megoldást, érdekelne. (Nekem ultimate-em van, így nem gond, de már a 2. ismerősöm fut ebbe bele.)
Egyszerű, ha tudod hol kell keresni.
Futtatni akartam pár régebbi unit tesztemet, de nem mentek, azt mondta, nem találja a Microsoft.ACE.OLEDB drivert. Tévesen több helyen azt láttam, hogy azt kell beírni, hogy Microsoft.ACE.OLEDB.14.0, de nem, a registryben is a régi, 12-es verzió van. Megnéztem, az InprocServer32 a C:\Program Files\Common Files\Microsoft Shared\OFFICE14\ACEOLEDB.DLL-re mutat, ami a manifestje alapján 64 bites C runtime dlleket használ, szóval tényleg van 64 bites access driver. (Az InprocServer32 név jó nagy fiaskó, minden ilyen bedrótozott verzió visszaüt később, mint a 16 bites shortParam, ami valójában 32 bites int).
Sejtettem, hogy 64 bit - 32 bit probléma van, de nem jöttem rá mi az oka, míg a tesztben ki nem írattam a teszt futtató bitszámát: Environment.Is64BitProcess == false.
Ekkor csaptam a homlokomra, hogy alapban 64 bites gépen is 32 bites processzben futnak a tesztek. De szerencsére át lehet állítani.
Ti ne töltsetek el 1 órát ilyen marhasággal, emlékezzetek erre. :)
Fenn van az MSDN-en, vigyük még meleg.
Játszottam kicsit az EF4-gyel. Az alábbi kód egy n rétegű app adatmozgását szimulálja a WCF xml szerializálóját használva. Mindhárom template-tel kipróbáltam, alább láthatóak az adatmozgások.
A tesztkód messze nem korrekt, de kiindulópontként további vizsgálatokhoz elfogatható:
using System;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
namespace POCO1
{
class Program
{
static void Main()
{
Department d;
using (var e = new SchoolEntities())
{
e.ContextOptions.ProxyCreationEnabled = false;
e.ContextOptions.LazyLoadingEnabled = false;
d = e.Departments.Include("Courses").Single(dep => dep.DepartmentID == 1);
Console.WriteLine("{0}", d.Name);
Console.WriteLine("---------------------");
foreach (Course c in d.Courses)
{
Console.WriteLine("{0}", c.Title);
}
e.Detach(d);
}
var ser = new DataContractSerializer(d.GetType());
//var ser = new DataContractSerializer(d.GetType(),
//null, 50000, true, true, null, new ProxyDataContractResolver());
using (var s2c = new FileStream(@"c:\temp\Server2Client.xml", FileMode.Create, FileAccess.ReadWrite))
{
//1. Server küld kliensre
ser.WriteObject(s2c, d);
s2c.Position = 0;
//2. Kliens deserializál
var clientSideDep = (Department)ser.ReadObject(s2c);
//Csak ST
//bool ce = clientSideDep.ChangeTracker.ChangeTrackingEnabled;
//3. Kliens módosít
clientSideDep.Name += "a";
using (var c2s = new FileStream(@"c:\temp\Client2Server.xml", FileMode.Create, FileAccess.ReadWrite))
{
//4. Kliens visszaküld
ser.WriteObject(c2s, clientSideDep);
c2s.Position = 0;
//5.Server deserializál
var sentBackDepartment = (Department)ser.ReadObject(c2s);
using (var e = new SchoolEntities())
{
//6. Server visszamódosít
//Normál entitás
e.Departments.Attach(sentBackDepartment);
e.ObjectStateManager.GetObjectStateEntry(sentBackDepartment).SetModified();
e.ObjectStateManager.GetObjectStateEntry(sentBackDepartment).SetModifiedProperty("Name");
//POCO
//e.Departments.Include("Courses").Single(dep => dep.DepartmentID == 1);
//e.Departments.ApplyCurrentValues(sentBackDepartment);
//Self-tracking entity
//e.Departments.ApplyChanges(sentBackDepartment);
e.SaveChanges();
}
}
}
}
}
}
EF alapobjektumok szerviz => kliens:
<Department z:Id="i1" xmlns="http://schemas.datacontract.org/2004/07/POCO1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<EntityKey z:Id="i2" xmlns="http://schemas.datacontract.org/2004/07/System.Data.Objects.DataClasses" xmlns:a="http://schemas.datacontract.org/2004/07/System.Data">
<a:EntityContainerName>SchoolEntities</a:EntityContainerName>
<a:EntityKeyValues>
<a:EntityKeyMember>
<a:Key>DepartmentID</a:Key>
<a:Value i:type="b:int" xmlns:b="http://www.w3.org/2001/XMLSchema">1</a:Value>
</a:EntityKeyMember>
</a:EntityKeyValues>
<a:EntitySetName>Departments</a:EntitySetName>
</EntityKey>
<Administrator>2</Administrator>
<Budget>350000.0000</Budget>
<Courses/>
<DepartmentID>1</DepartmentID>
<Name>Engineering</Name>
<StartDate>2007-09-01T00:00:00</StartDate>
</Department>
EF alapobjektumok kliens => szerviz:
<Department z:Id="i1" xmlns="http://schemas.datacontract.org/2004/07/POCO1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<EntityKey z:Id="i2" xmlns="http://schemas.datacontract.org/2004/07/System.Data.Objects.DataClasses" xmlns:a="http://schemas.datacontract.org/2004/07/System.Data">
<a:EntityContainerName>SchoolEntities</a:EntityContainerName>
<a:EntityKeyValues>
<a:EntityKeyMember>
<a:Key>DepartmentID</a:Key>
<a:Value i:type="b:int" xmlns:b="http://www.w3.org/2001/XMLSchema">1</a:Value>
</a:EntityKeyMember>
</a:EntityKeyValues>
<a:EntitySetName>Departments</a:EntitySetName>
</EntityKey>
<Administrator>2</Administrator>
<Budget>350000.0000</Budget>
<Courses/>
<DepartmentID>1</DepartmentID>
<Name>Engineeringa</Name>
<StartDate>2007-09-01T00:00:00</StartDate>
</Department>
POCO szerviz => kliens:
<Department xmlns="http://schemas.datacontract.org/2004/07/POCO1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> <Administrator>2</Administrator> <Budget>350000.0000</Budget> <Courses/> <DepartmentID>1</DepartmentID> <Name>Engineeringa</Name> <StartDate>2007-09-01T00:00:00</StartDate> </Department>
POCO kliens => szerviz:
<Department xmlns="http://schemas.datacontract.org/2004/07/POCO1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> <Administrator>2</Administrator> <Budget>350000.0000</Budget> <Courses/> <DepartmentID>1</DepartmentID> <Name>Engineeringaa</Name> <StartDate>2007-09-01T00:00:00</StartDate> </Department>
Self-tracking entity, szerviz => kliens:
<Department z:Id="i1" xmlns="http://schemas.datacontract.org/2004/07/POCO1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<Administrator>2</Administrator>
<Budget>350000.0000</Budget>
<ChangeTracker z:Id="i2">
<ExtendedProperties/>
<ObjectsAddedToCollectionProperties/>
<ObjectsRemovedFromCollectionProperties/>
<OriginalValues/>
<State>Unchanged</State>
</ChangeTracker>
<Courses/>
<DepartmentID>1</DepartmentID>
<Name>Engineeringaaaaaaaa</Name>
<StartDate>2007-09-01T00:00:00</StartDate>
</Department>
Self-tracking entity, kliens => szerviz:
<Department z:Id="i1" xmlns="http://schemas.datacontract.org/2004/07/POCO1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<Administrator>2</Administrator>
<Budget>350000.0000</Budget>
<ChangeTracker z:Id="i2">
<ExtendedProperties/>
<ObjectsAddedToCollectionProperties/>
<ObjectsRemovedFromCollectionProperties/>
<OriginalValues/>
<State>Modified</State>
</ChangeTracker>
<Courses/>
<DepartmentID>1</DepartmentID>
<Name>Engineeringaaaaaaaaa</Name>
<StartDate>2007-09-01T00:00:00</StartDate>
</Department>
Érdekes, hogy a módosítás ténye csak a ST-ben látszik, még az eredeti entity-sben sem. A POCO-tól nem is vártuk persze.
Később még majd foglalkozok bővebben a témával. Aki játszani akar vele, hozza létre a School EF példaadatbázist, azon lehet futtatni.
Többen kérdeztétek, pptben benne vannak a linkek a térképes demóm adataihoz és a konverziós eszközökhöz is.
Mellékeltem még a Running Aggregate SQL és CLR példát (kurzorral is, azt nem mutattam), a trade riportot az új chartocskákkal.
Letöltés innen (4 M).
És végre gyorsan jön, de lehet, hogy csak azért, mert alszanak még Amerikában.
Hogy aktuális legyen a VS 2010 konferencián bemutatott térkép-riport demóm, a vasárnapi választási eredményeket fogom térképen megjeleníteni. Tisztán interneten elérhető adatforrásokat, térképeket felhasználva. Izgi már a demót is összerakni. Véleményt nem fogok nyilvánítani, úgyis ismert, kikre szavazok.
Az demóadatok generálását delegáltam pár millió embernek, köszönet mindenkinek, aki dolgozik majd rajta. :)
Szétestem az utóbbi két hónapban, annyi munkám volt (elnézést kis családomtól így nyilvánosan is), de most végre kicsit fellélegzek. Most sok időm lesz, elvégre a munkák mellé csak 6 MCP vizsgát raktam be áprilisra (.NET 4 béták). :)
Májusban viszont újra lesz Design Patterns tanfolyam, ahol az eddigi a Gof patternek mellett Unityről és általában a Dependency Injection frameworkökről, ViewModelről, Composite Application Block for WPF-ről, T4 template alapú kódgenerálásról, partial method alapú kibővíthetőségről és Entity Framework Portable Extensible Metadatáról (egyfajta DSL) is szó lesz.
Várok mindenkit szeretettel.
Aki a NetAcademiánál jelentkezéskor az alábbi C# kód által kiírt stringet bemutatja, 50e Ft kedvezményt kap az árból.
using System;
class Program
{
static void Main(string[] args)
{
Allat a = new Emlos();
a.Mozog();
}
}
class Allat
{
public virtual void Mozog()
{
Console.WriteLine("Állat vagyok, és mozgok");
}
}
class Emlos : Allat
{
public virtual void Mozog()
{
Console.WriteLine("Emlős vagyok, és mozgok");
}
}
Mostanában oktatok és prototípust írok, közben ezer design kérdést tisztázok a fejemben. Az egyik ilyen pl., hogy a ViewModel DependencyProperty vagy INotifyPropertyChanged módon közvetítse a változásokat a GUI-ra?
Én az INotifyPropertyChanged-re szavaznék, mert így a ViewModel és nem függ a GUI technológiától, eleve nekem fura a modellben pl. WPF fogalmakat látni.
Infók a kérdéskörben.
Általános áttekintés:
INotifyPropertyChanged vs. DependencyProperty in ViewModel
Egy POCO szavazat:
View Models: POCOs versus DependencyObjects
Én Expressionnel oldom meg, hogy ne legyenek property name stringek a kódban, ő nem, de az objektum pool ötlet tetszik benne, átveszem, de szemeteljünk.
A base class which implements INotifyPropertyChanged
Nagyon dicsérik a videót, még nem volt időm megnézni.
Jason Dolinger on Model-View-ViewModel
Egyféle Validation megközelítés.
Using a ViewModel to Provide Meaningful Validation Error Messages
Ez igencsak bosszantó volt, remélem a fix megoldja.
Nekem nem tablet pcm van, mégis előjön.
https://connect.microsoft.com/VisualStudio/Downloads/DownloadDetails.aspx?DownloadID=26662
Link.
Most tervezek egy cégnek egy nagyobb architektúrát, és közben próbálom szem előtt tartani ezt a listát, könnyű beleesni a benne szereplő hibákba.
A következőn töröm a fejem. Az Entity Framework SSDL-jében definiálva vannak az entitás property-k alapvető jellemzői: nullázhatóság, max hossz. Ezeket a GUI-n ki kell kényszeríteni. Nyilván vannak összetettebb validálási szabályok, de most koncentráljunk ezekre az elemiekre.
Utálok minden redundanciát egy rendszerben, ezért azt gondoltam, a szabályokat kiolvasom az EF sémájából, és ebből táplálom meg a validáló részeket, így nem kell törődni az egyszerű validálásokkal, automatikusan működni fognak.
A következő kis kódocska mutatja meg a metaadatok használatát:
o.ForceLoadingSchemas();
var sspaceEntitySets = o.MetadataWorkspace
.GetItems<EntityContainer>(DataSpace.SSpace)
.First().BaseEntitySets.OfType<EntitySet>();
foreach (EntitySet es in sspaceEntitySets)
{
foreach (EdmProperty p in es.ElementType.Properties)
{
ReadOnlyMetadataCollection<Facet> facets = p.TypeUsage.Facets;
Debug.WriteLine("{0} is {1} nullable", p.Name, (bool)facets["Nullable"].Value ? "" : "not");
if (facets.Contains("MaxLength"))
{
Debug.WriteLine("{0} MaxLenght is {1}", p.Name, (int)facets["MaxLength"].Value);
}
Debug.WriteLine("{0} is {1} nullable", p.Name, (bool)facets["Nullable"].Value ? "" : "not");
}
}
A ForceLoadingSchemas az ObjectContext partial classában van:
public void ForceLoadingSchemas()
{
CreateQuery<BusinessEntity>("AdventureWorks2008Entities3.BusinessEntities").ToTraceString();
}
Csinált már valaki ilyet? Van benne valami csapda, amit most nem látok?
Error: Incorrect syntax near valami.
Akkor jön elő, ha az SQLCLR assemblyt és benne a függvényeket akarja az VS deployolni. Több oka lehet, most az volt, hogy egy .NET oldalon double-t visszaadó függvény véletlenül így lett deklarálva:
[SqlFunction(..., TableDefinition = "Datum datetime, Szazalek double")]
Mi a hiba benne? SQL Serverben nincs double, csak real és float. Ráadásul a C# float az az SQL real és a C# double az SQL Server float (kb.). :)
Az előbbi helyesen:
[SqlFunction(..., TableDefinition = "Datum datetime, Szazalek float")]
Miért kellett SQLCLR függvényt írni? A futó aggregálások (én legalábbis nem tudok jobbat kurzor nélkül) o(n2)-es algoritmusok, ezt CLR-ben könnyen meg lehet írni o(n)-re. Pl:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
public class UserDefinedFunctions
{
internal class Result
{
public long RowId;
public double CumDollarGain;
public double TopDollarGain;
public double DollarDrawDown;
}
//Input table: create table #trades(RowId long, DollarGain money, other columns possible)
[SqlFunction(FillRowMethodName = "FillRow", DataAccess = DataAccessKind.Read,
TableDefinition = "RowId bigint, CumDollarGain float, TopDollarGain float, DollarDrawDown float")]
public static IEnumerable Cumul()
{
using (var conn = new SqlConnection("Context connection=true"))
{
using (var cmd = new SqlCommand("select RowID, DollarGain from #trades", conn))
{
var res = new List<Result>();
conn.Open();
double cumulPrice = 0, topPrice = 0, drawDawn = 0;
using (SqlDataReader r = cmd.ExecuteReader())
{
int idCol = r.GetOrdinal("RowID");
int gainCol = r.GetOrdinal("DollarGain");
while (r.Read())
{
var price = r.GetDouble(gainCol);
cumulPrice += price;
topPrice = Math.Max(price, topPrice);
drawDawn += price;
drawDawn = Math.Min(drawDawn, 0);
res.Add(new Result
{
RowId = r.GetInt64(idCol),
CumDollarGain = cumulPrice,
TopDollarGain = topPrice,
DollarDrawDown = drawDawn
});
}
return res;
}
}
}
}
public static void FillRow(object obj,
out long id,
out double cumDollarGain,
out double topDollarGain,
out double dollarDrawDown)
{
var r = (Result)obj;
id = r.RowId;
cumDollarGain = r.CumDollarGain;
topDollarGain = r.TopDollarGain;
dollarDrawDown = r.DollarDrawDown;
}
};
Sajnos nem lehet átpasszolni a megnyitott SqlDataReadert a két metódus között, ezért kénytelen az ember letárolni az eredményhalmazt. Persze pár ezer sornál ez nem gond.