I PHP kan man ju otroligt enkelt dynamiskt skapa en publik variabel för en klass men är det möjlgt att göra något liknande i c#? Det går inte då C# är statiskt typat. Hej och tack för svaret! "Det finns flera fördelar med detta" Tack, det hade jag ingen aning om. Skulle det vara möjligt att vända på steken och istället loopa igenom kolumnerna från databasen och för varje kolumn kolla ifall propertyn finns och i så fall ge den ett värde? Eller blir det fortfarande samma problem om jag gör så? Har inte helt på grej det här med vad reflection är ännu. Så länge du använder reflection så KAN du få problem med prestandan. Men för de flesta vanliga applikationer är det inget problem, det är om man har krav på ordentlig prestanda som det kan ge ett problem. Och som vanligt så är det något man måste testa sig fram till. Med risk för att skriva det uppenbara... Ja läste lite på länkarna du skrev och det verkar vara precis det jag letar efter. Vad jag vet så kan inte EF hantera MySQL. Så i ditt fall så skulle jag rekomendera NHibernate, dels för den skall fungera mot MySQL och dels för att den är väldigt utbredd och det där med finns massor med information att finna på nätet när du kör fast. Jag har ägnat några timmar till att se vad det finns för alternativ och som du säger så verkar NHibernate vara den största open source på marknaden. "gör man en liten ändring i databasen måste man gå in i koden och ändra i både klassen och xml-filen." Jag har precis gjort mina första projekt med NHIbernate respektive Entity Framework. Det är visserligen lite äpplen och päron, men NHibernate är 10 gånger enklare när man väl kommit över första tröskeln. EF verkar smidigt så länge man kan klicka och dra, men så fort man stöter på minsta patrull är det ett rent h*lvete. I NHibernate kan du ha en mappnignsfil per tabell, i EF har en stor för hela din modell som är helt tröstlös att hitta i. SummerOfNHibernate var otroligt bra, jag gick igenom första videon utan några större problem. Angåend ISession så hittade jag denna kod ute på nätet.Dynamiska publika properties/variabler?
Låt oss säga att jag har en bas-klass My_Base_Item, denna klass har en funktion som heter load(int id) samt en property som heter table_Name (namnet på databastabellen).
Låt oss sedan säga att jag har en annan klass, My_News_Item som inheritar My_Base_Item.
I My_News_Item overridar jag table_Name och sätter det till 'news'.
Så när man kör My_News_Item.load(id) så ska basklassens load göra en select i stil med "select * from news where newsid = 5 limit 1". Men här kör jag fast, hur ska jag göra för att dynamiskt skapa variabler/properites baserat på vad databasen returnerar?
Vill alltså kunna göra något sånthär:
<code>
My_News_Item news_item = new My_News_Item();
news_item.load(5);
result.Text = news_item.NewsContent;
</code>
Den lösning jag använder just nu är att lägga allt i en DataRow och kallar på den såhär:
<code>
result.Text = Convert.ToString(news_item.Vars["NewsContent"]);
</code>
Men vill gärna slippa biten med att manuellt converta varje gång samt slippa att behöva hämta världet från en array/datarow.Sv: Dynamiska publika properties/variabler?
Man brukar lösa ditt problem genom att automatgenerera klassen eller dataset:et från databasschemat. Det blir inte dynamiskt förståss då du måste känna till databasstrukturen vid kompileringen.
VB.Net har late-binding så där skulle man dynamiskt kunna generera en klass som motsvarar databasen men jag vet inte om det finns något ramverk som gör det.
Nästa version av C# kommer att få en dynamisk datatyp som gör det något enklare. Du kommer dock fortfarande inte kunna skapa egenskaper men det blir möjligt att använda dynamiska sådana skapade i något annat språk (t.ex. ruby).Sv:Dynamiska publika properties/variabler?
Jag har googlat en hel del och kommit fram till en lösning jag är någorlunda nöjd med.
Jag har en parent/basklass samt en child klass som ärver basklassen.
I basklassen har jag en funktion som loopar genom alla properites och om dess namn matchar med en kolumn som hämtats från databasen fylls den med respektive världe.
Properties sätts i child klassen.
Det finns flera fördelar med detta, jag kan t.ex. bestämma vilka variabler som ska vara publika och vilka som ska vara protected. Jag kan också välja ifall jag inte vill att alla kolumner ska lagras i klassen.Sv: Dynamiska publika properties/variabler?
Det finns en nackdel också och det heter Reflection vilket i sin tur påverkar prestandan.
Din lösning är helt okej så länge du inte har grymma prestandakrav på din applikation eller kommer att ha MÅNGA samtidiga användare. Om du har det så kan du få problem med din lösning! Om inte kör på bara....
- MSv:Dynamiska publika properties/variabler?
Sv: Dynamiska publika properties/variabler?
- MSv:Dynamiska publika properties/variabler?
Det vanligaste sättet att bygga en C# lösning som går mot en databas är du att lägga ett DAL (Data Access Layer) med objekt som representerar den data du har i din databas. Du får då starkt typade objekt och en mycket robustare kodbas.
Dessvärre blir det snabbt långtråkigt att skriva objekt för alla tabeller man slänger ihop. Det är inte svårt men det känns som om man hela tiden skriver samma kod med olika namn på variablerna.
För att motverka det finns sk OR-Mappers (http://en.wikipedia.org/wiki/Object-relational_mapping), t ex nhibernate och MS Entity Framework (http://en.wikipedia.org/wiki/ADO.NET_Entity_Framework).
En OR-mapper generar ett DAL åt dig automatiskt utifrån din databas.
Om detta är bra eller dåligt kan man tvista om till förbannelse, men i korta drag kan man säga att när man kan sin ORMapper så går det sjukt snabbt att använda den och man brukar älska effektiviteten bakom.
Är man dock ny på banan kan det kännas övermäktigt att få grepp om vad som egentligen sker i mappern - de första 95% av ditt projekt går otroligt snabbt, men de sista justeringarna kan kräva att du får bända och kränga på din kod för att passa in den i mapperns beteende.
/HWSv: Dynamiska publika properties/variabler?
Vilken ORM skulle du/ni rekommendera för mysql+c#? Kan man använda ADO.NET Entity Framework? Eller är den starkt bunden till access / ms sql?Sv:Dynamiska publika properties/variabler?
- MSv: Dynamiska publika properties/variabler?
Men nu undrar jag vad det är som gör den bättre än de andra (förutom att den används av många och har en lång bakgrund).
Jämfört med en del andra verkar den krånglig att underhålla, gör man en liten ändring i databasen måste man gå in i koden och ändra i både klassen och xml-filen.
Jag baserar mina uppfattningar på:
http://www.devsource.com/c/a/Techniques/Getting-Started-with-NHibernate/1/
som var det enda konkreta lättförstådda exempel jag hittade.Sv:Dynamiska publika properties/variabler?
Anledningen till att man använder sig av ORM och mappningsfiler är att du skall slippa ändra både i databasen och i klassen om du gör förändringarn någonstans.
Om du gör en förändring i databasen så räcker det (oftast) med att förändra i mappningsfilen för att förändringen skall fungera, det är det som är själva poängen. Men allt beror ju på hur mycket du förändrar.
Visst kan den verka jobbig och komplex till en början, men det beror på att den kan så mycket som du säkert inte kommer använda dig av på mycket länge, det är ungeför som WORD 80 % av alla användare använder 20 % av funktionaliteten. De sista 20 % är de som driver på utvecklingen. :)
Om du vill komma snabbare igång och inte vill hålla på med mappningsfiler så är det LinqToSql som gäller för dig, men tyvärr så tror jag inte MySQL fungerar där heller så fall får du byta db till MS SQL Express som är gratis.
Jag tror att om du ger NHibernate en chans så har du inom 2 dagar fått till en lösning som är bättre än den du har idag, och det är det värt. Här är en bra site att börja lära dig NHibernate (http://www.summerofnhibernate.com/)
- MSv:Dynamiska publika properties/variabler?
Nämnas kan att Linq-stödet är väldigt dåligt i båda alternativen, så tycker du det är viktigt ska du nog kika på andra alternativ.Sv: Dynamiska publika properties/variabler?
Nu är min fråga mera hur man bör bygga upp sin DAL (Data Access Layer).
Behöver man initiera ISession i varje metod eller kan man lägga den i t.ex. en statisk klass? Hur är det rekommenderade sättet att jobba?
Hur ska man strukturera upp det? I SummerOfNHibernate-guiden verkade tankesättet vara att man har en enda stor klass med alla metoder, t.ex. loadCustomerById(). Blir inte en sån fil något helvetes stor och svår att jobba med?Sv:Dynamiska publika properties/variabler?
<code>
using System.Runtime.Remoting.Messaging;
using System.Web;
using NHibernate;
using NHibernate.Cache;
using NHibernate.Cfg;
namespace BL.Portal.Infrastructure.Repository.NHibernate
{
/// <summary>
/// Handles creation and management of sessions and transactions. It is a singleton because
/// building the initial session factory is very expensive. Inspiration for this class came
/// from Chapter 8 of Hibernate in Action by Bauer and King. Although it is a sealed singleton
/// you can use TypeMock (http://www.typemock.com) for more flexible testing.
/// </summary>
public sealed class NHibernateSessionManager
{
//-- Declaration
private const string TRANSACTION_KEY = "CONTEXT_TRANSACTION";
private const string SESSION_KEY = "CONTEXT_SESSION";
private ISessionFactory sessionFactory;
//-- Properties
/// <summary>
/// If within a web context, this uses <see cref="HttpContext" /> instead of the WinForms
/// specific <see cref="CallContext" />. Discussion concerning this found at
/// http://forum.springframework.net/showthread.php?t=572.
/// </summary>
private ITransaction ContextTransaction
{
get
{
if (IsInWebContext())
{
return (ITransaction)HttpContext.Current.Items[TRANSACTION_KEY];
}
else
{
return (ITransaction)CallContext.GetData(TRANSACTION_KEY);
}
}
set
{
if (IsInWebContext())
{
HttpContext.Current.Items[TRANSACTION_KEY] = value;
}
else
{
CallContext.SetData(TRANSACTION_KEY, value);
}
}
}
/// <summary>
/// If within a web context, this uses <see cref="HttpContext" /> instead of the WinForms
/// specific <see cref="CallContext" />. Discussion concerning this found at
/// http://forum.springframework.net/showthread.php?t=572.
/// </summary>
private ISession ContextSession
{
get
{
if (IsInWebContext())
{
return (ISession)HttpContext.Current.Items[SESSION_KEY];
}
else
{
return (ISession)CallContext.GetData(SESSION_KEY);
}
}
set
{
if (IsInWebContext())
{
HttpContext.Current.Items[SESSION_KEY] = value;
}
else
{
CallContext.SetData(SESSION_KEY, value);
}
}
}
//-- Methods
#region Thread-safe, lazy Singleton
/// <summary>
/// This is a thread-safe, lazy singleton. See http://www.yoda.arachsys.com/csharp/singleton.html
/// for more details about its implementation.
/// </summary>
public static NHibernateSessionManager Instance
{
get
{
return Nested.NHibernateSessionManager;
}
}
/// <summary>
/// Initializes the NHibernate session factory upon instantiation.
/// </summary>
private NHibernateSessionManager()
{
InitSessionFactory();
}
/// <summary>
/// Assists with ensuring thread-safe, lazy singleton
/// </summary>
private class Nested
{
static Nested() { }
internal static readonly NHibernateSessionManager NHibernateSessionManager =
new NHibernateSessionManager();
}
#endregion
private void InitSessionFactory()
{
sessionFactory = new Configuration().Configure().BuildSessionFactory();
}
/// <summary>
/// Allows you to register an interceptor on a new session. This may not be called if there is already
/// an open session attached to the HttpContext. If you have an interceptor to be used, modify
/// the HttpModule to call this before calling BeginTransaction().
/// </summary>
public void RegisterInterceptor(IInterceptor interceptor)
{
ISession session = ContextSession;
if (session != null && session.IsOpen)
{
throw new CacheException("You cannot register an interceptor once a session has already been opened");
}
GetSession(interceptor);
}
public ISession GetSession()
{
return GetSession(null);
}
/// <summary>
/// Gets a session with or without an interceptor. This method is not called directly; instead,
/// it gets invoked from other public methods.
/// </summary>
private ISession GetSession(IInterceptor interceptor)
{
ISession session = ContextSession;
if (session == null)
{
if (interceptor != null)
{
session = sessionFactory.OpenSession(interceptor);
}
else
{
session = sessionFactory.OpenSession();
}
ContextSession = session;
}
//Check.Ensure(session != null, "session was null");
return session;
}
/// <summary>
/// Flushes anything left in the session and closes the connection.
/// </summary>
public void CloseSession()
{
ISession session = ContextSession;
if (session != null && session.IsOpen)
{
session.Flush();
session.Close();
}
ContextSession = null;
}
public void BeginTransaction()
{
ITransaction transaction = ContextTransaction;
if (transaction == null)
{
transaction = GetSession().BeginTransaction();
ContextTransaction = transaction;
}
}
public void CommitTransaction()
{
ITransaction transaction = ContextTransaction;
try
{
if (HasOpenTransaction())
{
transaction.Commit();
ContextTransaction = null;
}
}
catch (HibernateException)
{
RollbackTransaction();
throw;
}
}
public bool HasOpenTransaction()
{
ITransaction transaction = ContextTransaction;
return transaction != null && !transaction.WasCommitted && !transaction.WasRolledBack;
}
public void RollbackTransaction()
{
ITransaction transaction = ContextTransaction;
try
{
if (HasOpenTransaction())
{
transaction.Rollback();
}
ContextTransaction = null;
}
finally
{
CloseSession();
}
}
private bool IsInWebContext()
{
return HttpContext.Current != null;
}
}
}
</code>
Tror den fungerar bra, är inte så jätte insatt i NHibernate.
Angående metoderna så skapar du en sådan klass per domänklass du har. Säg att du har Customer och Order, då får du ett CustomerRepository och ett OrderRepository där du har de olika metodern. LoadCustomerByid() (CustomerRepositoryt) och LoadOrderByCustomerId() (OrderRepositoryt).
- M