Gladh skrev:
Mapperklassen konveterar objektet till rätt typ och sätter sen alla properties. Så istället för setValue så blir det ex. item.Name = reader(2);
Walker, jag gör som din första beskrivning, har attribut på alla variabler, och läser in dessa i en cache. Och med SetValue så sätter jag datan.
Däremot så blir jag riktigt intresserad av ovanstående: item.name = reader(2);
Jag har letat efternågot sånt. Att matcha ihop reader(2) och name är ingen konst, det är att göra en dynamisk: item.name som blir svår. Eller är detta något som skapas för varje klass, så om du har 2 klasser så får du 2 stycken funktioner, alltså en funktion som fyller klass1 och en som fyller klass2 och dessa funktioner skapas som kod utifrån klasserna. Alltså lite som en codegen.
Har du en länk till sisyphus så man kan se hur de har gjort?
- magnus
Hej
Yepp, det är ungefär så som du beskriver som jag gjort..
Men jag tror jag vilseledde dig lite innan.. men här kommer lite kod och kommentarer
Om du laddar ner koden för sisyphus så ta den som finns i cvs'en, den andra fungerar inte. (den kanske fungerar men den är out of date)
Allting händer i klassen SpfEntityStorageDefn och det är metoden PopulateEntity som jag ändrat i.
public void PopulateEntity(IDataReader p_Reader, SpfEntity p_Entity)
{
this.Populate(p_Reader, p_Entity);
// foreach (SpfFieldDefn fieldDefn in m_FieldDefns) {
// if (fieldDefn.IsLoaded) {
//
// object fieldValue;
// if (p_Reader[fieldDefn.ColumnName] == DBNull.Value) {
// fieldValue = null;
// }
// else {
// fieldValue = fieldDefn.DataType.ConvertValue(p_Reader[fieldDefn.ColumnName]);
// }
//
// fieldDefn.Member.SetValue(p_Entity, fieldValue);
//
// }
// }
}
Som du ser så anropar jag populate som ser ut så här
private void Populate(IDataReader p_Reader, SpfEntity p_Entity)
{
IMap _currentMapper = MappersCollection.GetMapper(p_Entity.GetType());
p_Entity = _currentMapper.Populate( p_Reader, p_Entity, this.m_FieldDefns);
}
Vidare..
public static IMap GetMapper(System.Type type)
{
if (_mappers == null)
{
InitMappers();
}
IMap currentMapper = (IMap)_mappers[type];
if (currentMapper != null)
{
return currentMapper;
}
else
{
return _defaultMapper;
}
}
_defaultMapper är egentligen den koden som finns i PopulateEntity i SpfEntityStorageDefn klassen, men inkapslad i en klass och i denna så har sist i koden lagt in.
#if DEBUG
WriteXml(fieldDefs, entity);
#else
// gör inget.
#endif
från den xmlfilen som skrivs ut så skapar jag sedan en mappningsklass som ser ut som följer. Denna lägger jag till sedan i MappersCollection, antingen så genererar jag denna också mha codesmith eller så lägger jag till dem för hand.
public class UserMap : Sisyphus.IMap
{
public UserMap()
{
}
public Sisyphus.SpfEntity Populate(System.Data.IDataReader reader, Sisyphus.SpfEntity user, SpfFieldDefn[] fieldDefs)
{
BO.User usr = (BO.User)user;
usr.Name = reader["name"].ToString();
return ( Sisyphus.SpfEntity)usr;
}
}
det är ett tag sedan jag gjord detta, la ner det pga sisyphus innehöll för mycket buggar som jag aldrig orkade rätta, om jag ens kunde hitta vart det gick fel.. och det är egentligen väldigt enkelt gjort..
Nackdelarna är att man alltid måste dra med sig sisyphusprojektet så att detta finns i samma sln som ens affärslogik och man skapar en ganska hård koppling mellan bl och dl.. men det fungerade för mig. Man kan nog lösa det genom att trixa lite med interfaces, men la ner det hela pga buggar och att det kom lite andra saker emellan..
Jag har inte testat om man kan göra samma sak med collections men det borde fungera.. Men som sagt, koden är inte 100%, ser nu att null hantering inte finns med och inga try and catch, osv.. men men..