giovedì 19 gennaio 2012

Linq To Sql. Delete Parent and Child part 1

Questa cosa secondo me non l'hanno gestita bene, o non l'ho gestita bene io.
Di contro mi aspettavo qualcosa di utile come una delete condizionale.

static void Main(string[] args)
{
PmPlusDataContext pm = new PmPlusDataContext();

pm.Fornitoris.InsertOnSubmit(new Fornitori() {
Indirizzo = "via Dei Dati sporchi",
Ragione_Sociale = "Linq To Sql",
Recapito_Mail = "info@microsoft.com",
Recapito_Mobile = "00 00 000000",
Riferimento = "Gugliemo Cancelli",
Telefono_Sede = "00 000 0000 00" });

// Effettivo inserimento
pm.SubmitChanges();

// senza submit il dato non è fisicamente scritto su db
// di contro questa fallisce
var fx = pm.Fornitoris.Single(
f => f.Ragione_Sociale == "Linq To Sql"
);

fx.Risorses.Add(new Risorse() {
Cognome = "Risorsa",
Nome = "Umana 1",
CostoGiorno = 120,
CostoOra = 10,
idAmbitoDefault = 0,
idRisorsa = 1,
idRuoloDefault = 0 });

fx.Risorses.Add(new Risorse(){
Cognome = "Risorsa",
Nome = "Umana 2",
CostoGiorno = 120,
CostoOra = 10,
idAmbitoDefault = 0,
idRisorsa = 1,
idRuoloDefault = 0 });

fx.Risorses.Add(new Risorse() {
Cognome = "Risorsa",
Nome = "Umana 3",
CostoGiorno = 120,
CostoOra = 10,
idAmbitoDefault = 0,
idRisorsa = 1,
idRuoloDefault = 0
});

Console.WriteLine("Risorse prima della commit:" +
pm.Risorses.Count().ToString());

// come per il fornitore solo così salviamo il dato
pm.SubmitChanges();

Console.WriteLine("Risorse dopo la commit:" +
pm.Risorses.Count().ToString());



// cosa non troppo elegante ..
// mi aspettavo una delete con condizione...
var res = pm.Risorses.Where(r => r.idFornitore == fx.idFornitore);
foreach (Risorse r in res)
pm.Risorses.DeleteOnSubmit(r);

// sempre peggio
pm.Fornitoris.DeleteOnSubmit(fx);


Console.WriteLine("Risorse dopo la delete:" +
pm.Risorses.Count().ToString());

pm.SubmitChanges();

Console.WriteLine("Risorse dopo la commit:" +
pm.Risorses.Count().ToString());
Console.ReadKey();
}


Di contro benchè si tratti di un banale esempio .. giusto per comprendere il funzionamento di LinqToSql ( fatta eccezione per la ridicola "S" in coda ad ogni tabella... mi sarei atteso qualcosa di più "ehm" vicino all' Sql.

var res = fx.Risorses.ToList();

// e questo dove lo mettiamo ??
foreach (Risorse r in res)
pm.Risorses.DeleteOnSubmit(r);

Console.WriteLine("Risorse dopo la delete:" +
pm.Risorses.Count().ToString());

// sempre peggio
pm.Fornitoris.DeleteOnSubmit(fx);


Tuttavia si può optare anche per questa soluzione che forse sembra migliore, tuttavia rimango decisamente colpito dall'assenza di una "condizionale" per la Delete.

Magari in futuro .. non si sa mai che qualcosa arrivi..

martedì 17 gennaio 2012

How To: Get Center of a String.

Un collega mi ha chiesto come trovare il carattere centrale di una stringa, di contro la richiesta è semplice, ma ci sono vari modi per ottenere lo stesso risultato.

In alcuni casi ci si può fare del male, in altri si può sperare che con un colpo vada tutto bene...

C'e' da ricordarsi "sempre" che una string è comunque un array di char e quindi ...

class Program
{
static void Main(string[] args)
{
string test = " abcdefghilmnopqrstuvz ";

//Complesso ma non troppo
int c = Convert.ToInt32(
test.TrimStart(
new char[] { ' ' }
).TrimEnd(
new char[] { ' ' }
).ToCharArray().Length / 2);

char res = test.TrimStart(
new char[] { ' ' }
).TrimEnd(
new char[] { ' ' }
).ToCharArray()[c];

//Semi "professional"
int c1 = Convert.ToInt32(
test.Trim().ToCharArray().Length / 2);

char res1 = test.Trim().ToCharArray()[c1];


// Pro
int c2 = Convert.ToInt32(
test.Replace(" ","").ToCharArray().Length / 2);

char res2 = test.Trim().ToCharArray()[c2];



Console.WriteLine(res);
Console.WriteLine(res1);
Console.WriteLine(res2);

// ADVANCED !!
Console.WriteLine(test.Trim()[Convert.ToInt32(test.Length / 2)]);
Console.ReadKey();
}
}


Quindi ecco alcune possibili soluzioni.

Il problema generalmente non sta nel non sapere le cose, ma nel non chiedere !

lunedì 16 gennaio 2012

How To:Direct X

Ecco il primo giro di prova su Direct X !

Giusto per comprendere come funziona questo "chiodo" e dopo svariati tentativi http://www.blogger.com/img/blank.gifsu XNA, mi sono deciso nel voler fare delle prove direttamente da visual studio 2010.

Per poter fare questa prova vi serve sicuramente "DirectX for Managed Code" che tuttavia non appartiene al Framework 4.0 ma al 1.1.4322 il che vi porta al post:
Solved:Mixed mode assembly nel caso stiate usando un framework differente dal 4.0.

Ciò detto:
Create una Window Application,
Aggiungete le reference del framework (Direct X),
E procediamo così per gradi:

Il form:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

namespace TestDX
{
public partial class frmTestDX : Form
{
public Device dx = null;

public frmTestDX()
{
InitializeComponent();
}


public void InitGraphics()
{
PresentParameters ps = new PresentParameters();
ps.Windowed = true;
ps.SwapEffect = SwapEffect.Discard;

dx = new Device(0, DeviceType.Hardware,
this,
CreateFlags.SoftwareVertexProcessing,
ps);
}


protected override void OnPaint(PaintEventArgs e)
{
dx.Clear(ClearFlags.Target,
System.Drawing.Color.DimGray,
1.0F,
0);
dx.Present();
}
}
}


Tutto il codice scritto serve esclusivamente a inizializzare la struttura Device,
che di contro è il nostro piano di riferimento.
L'entry point di un applicazione XNA.

E questo è il Main :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace TestDX
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
frmTestDX fx = new frmTestDX();
Application.EnableVisualStyles();
fx.InitGraphics();
Application.Run(fx);
}
}
}


Come noterete c'e' qualche differenza rispetto al solito:
"Application.SetCompatibleTextRenderingDefault(false);"
Questa è stata completamente rimossa, perchè tecnicamente non serve.

Bene che cosa ci serve ( se non siamo incappati nel problema Solved:Mixed mode assembly ) ci basta solo premere l'avvio.

Di contro è il primo esempio e otteremo uno sfondo grigio!

Solved: Mixed mode assembly is built against version

Nell'ottica di testare DirectX (Framework 1.1.4322 mi sono imbattuto in quest'errore.

Mixed mode assembly is built against version 'v1.1.4322' of the runtime and cannot be loaded in the 4.0 runtime without additional configuration information.

Ho fatto qualche ricerca, ma onestamente con poca fiducia, tuttavia ho risolto senza impazzire.

Quello che serve è:
Aggiungere "App.config"
Assicurarsi che contenga :

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>


Non basta fare un restart dell'applicazione, è necessario ricompilare ed esegure nuovamente l'applicazione.

E a questo punto il problema "scompare".

mercoledì 4 gennaio 2012

How To: Dynamic Class programmatically (2.0)

Questa mattina di buona lena mi sono messo in mente di verificare il funzionamento della precedente versione e mi sono accorto di alcuni problemi / errori che con questa versione risultano corretti.

Uno dei grossi problemi di questo blog è l'impossibilità di inserire gli allegati, di contro quindi pubblico tutta la soluzione in modo da dare qualche spigazioncina in più.

progetto XA.EF_Commons

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace XA.EF_Commons.Entities
{
public class _EntitiesType:List<_EntityType>
{
}
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace XA.EF_Commons.Entities
{
public class _EntityPropertyType
{
public string propertyName { get; set; }
public string propertyType { get; set; }
public bool readOnly { get; set; }
public string propertyComment { get; set; }
}
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace XA.EF_Commons.Entities
{
public class _EntityType
{
public string className { get; set; }
public string classComment { get; set; }
public bool hasCollection { get; set; }
public List<_EntityPropertyType> classProperties =
new List<_EntityPropertyType>();
}
}


Mi sono anche premurato di creare un interfaccia per il builder nel caso mi venisse voglia di creare qualcosa di differente pur lasciando la vecchia modalità.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace XA.EF_Commons
{
public interface IBuilder
{
void Build(
string Namespace,
out string[] errors,
out string libraryPath,
out string sourceCode,
XA.EF_Commons.Entities._EntitiesType el
);
}
}


Questa parte del processo è dedicata alla creazione della libreria...


using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;
using Microsoft.CSharp;
using System.CodeDom;
using System.CodeDom.Compiler;

namespace XA.EF_Core.Builder
{
public class Builder : XA.EF_Commons.IBuilder
{

/// <summary>
/// Metodo Build
/// </summary>
/// <param name="Namespace">Namespace del progetto</param>
/// <param name="errors">OUT Errori in generazione</param>
/// <param name="libraryPath">OUT Percorso della libreria</param>
/// <param name="sourceCode">OUT Codice Sorgente</param>
/// <param name="el">Collezione di Entità da realizzare</param>
public static void Build(
string Namespace,
out string[] errors,
out string libraryPath,
out string sourceCode,
XA.EF_Commons.Entities._EntitiesType el
)
{
CSharpCodeProvider cProvider = new CSharpCodeProvider();
ICodeCompiler cCompiler = cProvider.CreateCompiler();

CompilerParameters parameters = new CompilerParameters();
parameters.ReferencedAssemblies.Add("System.dll");
parameters.GenerateInMemory = false;

CodeCompileUnit unit = new CodeCompileUnit();
unit.ReferencedAssemblies.Add("System.dll");

CodeNamespace customEntityRoot = new CodeNamespace(Namespace);
unit.Namespaces.Add(customEntityRoot);

customEntityRoot.Imports.Add(
new CodeNamespaceImport("System"));
customEntityRoot.Imports.Add(
new CodeNamespaceImport("System.Collections.Generic"));


foreach (XA.EF_Commons.Entities._EntityType e in el)
{
CodeTypeDeclaration Entity = new CodeTypeDeclaration(e.className);
customEntityRoot.Types.Add(Entity);

for (int i = 0; i < e.classProperties.Count; i++)
{
CodeMemberField cf = new CodeMemberField();
cf.Attributes = MemberAttributes.Private;
cf.Name = "_" + e.classProperties[i].propertyName;
cf.Type = new CodeTypeReference(
e.classProperties[i].propertyType);
Entity.Members.Add(cf);


CodeMemberProperty cp = new CodeMemberProperty();
cp.Name = e.classProperties[i].propertyName;
cp.Type = new CodeTypeReference(
e.classProperties[i].propertyType);
cp.HasGet = true;
cp.GetStatements.Add(new CodeMethodReturnStatement(
new CodeFieldReferenceExpression(null,cf.Name)));
cp.HasSet = true;
cp.SetStatements.Add(new CodeAssignStatement(
new CodeFieldReferenceExpression(null, cf.Name),
new CodeFieldReferenceExpression(null, "value")));

cp.Attributes = MemberAttributes.Public;

Entity.Members.Add(cp);
}

CodeTypeDeclaration EntityList = new CodeTypeDeclaration(
e.className + "_List");
customEntityRoot.Types.Add(EntityList);

CodeTypeReference baseClass = new CodeTypeReference(
"List<"+e.className+">");
EntityList.BaseTypes.Add(baseClass);
}

ICodeGenerator cGenerator = cProvider.CreateGenerator();
StringBuilder generatedCode = new StringBuilder();
StringWriter cWriter = new StringWriter(generatedCode);
CodeGeneratorOptions options = new CodeGeneratorOptions();
options.BracingStyle = "C";
cGenerator.GenerateCodeFromCompileUnit(unit, cWriter, options);

CompilerResults results = cProvider.CompileAssemblyFromSource(
parameters,
generatedCode.ToString()
);



sourceCode = generatedCode.ToString();

libraryPath = results.PathToAssembly;


errors = new string[results.Output.Count];
for (int i = 0; i < results.Output.Count; i++)
{
errors[i] = results.Output[i];
}

cProvider = null;
cCompiler = null;
parameters = null;
cGenerator = null;
cWriter = null;

}
}
}



Non è difficile notare la presenza di due nuovi elementi.
a) CodeMemberField cf = new CodeMemberField();
Che rappresenta il campo interno rimappato dall'entità
b) cp.GetStatements & cp.SetStatements
Che rappresentano i due corpi del set e del get.

Lo scopo di questa breve soluzione, è quello di restituire il nome della dll buildata ed eventualmente gli errori.

Chiaramente se gli errori sono "pieni" dovranno essere cominicati.. caso contrario la libreria sarà disponibile.
Il suggerimento è quello di copiare la libreria nella directory di rilascio e quindi di linkarla al progetto.

martedì 3 gennaio 2012

How To: Dynamic Class programmatically

Su questo argomento mi sono sbattuto fino a che non ho trovato quello che realmente stavo cercando ...

L'idea di base è di costruirsi a RunTime delle Classi banalmente Entity con Get e Set, di contro tutto quello che ho trovato su WEB, mi ha sempre lasciato perplesso, tremendamente perplesso. Quintali e quintali di codice poco comprensibili.

Rimango dell'idea ( sfide a parte ) che il codice debba comunque essere leggibile e a tal proposito chi deve leggere deve comprendere ciò che sta leggendo.

Ciò detto .. ecco il quanto.

Questa semplice ma pur efficace console application serve a mostrare come generare una classe Entity partendo da una definizione (che potrebbe essere frutto di un XML).

Framework: 4.0
Reference:Microsoft.CSharp


using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Microsoft.CSharp;
using System.CodeDom;
using System.CodeDom.Compiler;

namespace cDynamicType
{

public class entity
{
public string className { get; set; }
public string classNamespace { get; set; }
public List<entityPropertyType> classProperties = new List<entityPropertyType>();
}

public class entityPropertyType
{
public string propertyName { get; set; }
public string propertyType { get; set; }
public bool readOnly { get; set; }
}

class Program
{
static void Main(string[] args)
{

entity e = new entity();
e.className = "entityTest";
e.classNamespace = "Test.Entities";
e.classProperties.Add(new entityPropertyType() {
propertyName = "ID",
propertyType = "Int32",
readOnly = false });

e.classProperties.Add(new entityPropertyType() {
propertyName = "Name",
propertyType = "System.string",
readOnly = false });

e.classProperties.Add(new entityPropertyType() {
propertyName = "Description",
propertyType = "System.string",
readOnly = false });


CSharpCodeProvider cProvider = new CSharpCodeProvider();
ICodeCompiler cCompiler = cProvider.CreateCompiler();

CompilerParameters parameters = new CompilerParameters();
parameters.ReferencedAssemblies.Add("System.dll");

CodeCompileUnit unit = new CodeCompileUnit();
unit.ReferencedAssemblies.Add("System.dll");

CodeNamespace customEntityRoot = new CodeNamespace(e.classNamespace);
unit.Namespaces.Add(customEntityRoot);

customEntityRoot.Imports.Add(new CodeNamespaceImport("System"));

CodeTypeDeclaration Entity = new CodeTypeDeclaration(e.className);
customEntityRoot.Types.Add(Entity);

CodeConstructor EntityClassConstructor = new CodeConstructor();
EntityClassConstructor.Attributes = MemberAttributes.Public;


for (int i = 0; i < e.classProperties.Count; i++)
{
CodeMemberProperty cp = new CodeMemberProperty();
cp.Name = e.classProperties[i].propertyName;
cp.Type = new CodeTypeReference(e.classProperties[i].propertyType);
cp.HasGet = true;
cp.HasSet = true;

Entity.Members.Add(cp);
}


ICodeGenerator cGenerator = cProvider.CreateGenerator();
StringBuilder generatedCode = new StringBuilder();
StringWriter cWriter = new StringWriter(generatedCode);
CodeGeneratorOptions options = new CodeGeneratorOptions();
options.BracingStyle = "C";
cGenerator.GenerateCodeFromCompileUnit(unit, cWriter, options);


CompilerResults results = cProvider.CompileAssemblyFromSource(
parameters,
generatedCode.ToString()
);

Console.WriteLine(generatedCode.ToString());

Console.WriteLine(results.PathToAssembly);

Console.ReadKey();

cProvider = null;
cCompiler = null;
parameters = null;
cGenerator = null;
cWriter = null;
}
}
}



Le prime due classi mi servono per rappresentare l'entità di cui fare il render.
di cui entity si porta dietro poco nulla se non il nome della classe, il namespace e le propretà. La seconda sono le proprietà.

Il processo è semplice:
crea il provider,
crea il compiler,
crea il namespace,
aggiunge le referenze,
aggiunge le using,
crea le proprietà,
compila.

Cosa Manca, certo questo codice come sempre o quasi pecca in molto perchè non è del tutto completo tuttavi può essere un buon spunto su cui ragionare.

How To: Use StringBuilder

Di tanti oggetti comodi questo protrebbe risultare il meno utile tuttavia ha delle potenzialità nascoste.

Lo StringBuilder consente di costruire una stringa partendo da un valore iniziale, tecnicamente noto.

Fra i vari metodi uno risulta essere davvero comodo e consente di inserire una serie di caratteri in un determinato punto. La parte interessante di questo comando è la possibilità di "quantificare" il numero di caratteri in oggetto.

StringBuilder s new StringBuilder("TESTO")
Console.WriteLine (s.Insert(0, "\t", 2).ToString());
Console.WriteLine (s.Insert(5, "\t", 2).ToString()+"*");


Questo semplice esempio mostra come aggiungere in testa o in coda dei tab.

Questo metodo può tornare comodo soprattutto in fase di costruzione di semplici report testuali o nell'indentazione di file di log.