NOVINKA! E-learningové kurzy umělé inteligence. Nyní AI za nejlepší ceny. Zjisti více:
NOVINKA – Víkendový online kurz Software tester, který tě posune dál. Zjisti, jak na to!
Avatar
Neaktivní uživatel:14.8.2017 15:42

Ahoj, mám aplikaci, která stahuje data do data readeru a následně z data readeru mapuje data do tříd pomocí atributů. Vše funguje perfektně...až doteď - někteří moji kolegové nemohou apku použít.
Exception message přikládám jako obrázek.
StackTrace mě dovedl k mé metodě na mapování - bohužel neuvádí číslo řádku kde je chyba...
Metoda pro mapování kde chyba vznikne podle stacktrace vypadá takto:

public IEntity MapToClass(SqlDataReader reader)
{
    IEntity returnedObject = Activator.CreateInstance<IEntity>();
    PropertyInfo[] modelProperties = returnedObject.GetType().GetProperties();
    for (int i = 0; i < modelProperties.Length; i++)
    {
        MappingAttribute[] attributes = modelProperties[i].GetCustomAttributes<MappingAttribute>(true).ToArray();

        if (attributes.Length > 0 && attributes[0].ColumnName != null)
        {
            modelProperties[i].SetValue(returnedObject, ChangeType(reader[attributes[0].ColumnName], modelProperties[i].PropertyType), null);
        }

    }
    return returnedObject;
}

Bohužel sem začátečník a trhám si nad touto chybou vlasy...na drtivě většině našich strojů to jede bezproblémově, mám podezření, že chyba není v kódu jako takovém...ale co s tím?

Odpovědět
14.8.2017 15:42
Neaktivní uživatelský účet
Avatar
Neaktivní uživatel:14.8.2017 15:57

Už chápu kde je problém, můj projekt je cílený na net.framework 4.5 - změnil sem cíl na 4.0 a metoda nyní nefunguje...

Nahoru Odpovědět
14.8.2017 15:57
Neaktivní uživatelský účet
Avatar
Neaktivní uživatel:14.8.2017 16:15

Tak sem aktuálně nahradil ...

MappingAttribute[] attributes = modelProperties[i].GetCustomAttributes<MappingAttribute>(true).ToArray();

Tímto:

MappingAttribute[] attributes = Array.ConvertAll(modelProperties[i].GetCustomAttributes(typeof(MappingAttribute), true).ToArray(), s => (MappingAttribute)s);

Aplikace nyní funguje - ale příjde mi, že došlo ke zpomalení... :(

Editováno 14.8.2017 16:17
Nahoru Odpovědět
14.8.2017 16:15
Neaktivní uživatelský účet
Avatar
Neaktivní uživatel:14.8.2017 21:09

Ake je to spomalenie? O 20, o 50%? Je to spomalenie citelne?
Osobne by som skor pouzil pristup cez SqlDataAdapter s Fill funkciou do DataSetu. Nasledne for (!) cyklus nad datarow, v kazdom cykle vytvorit instanciu, zjistit properties, pak atributy.
V ramci 'SetValue' nemusis pouzivat ChangeType, framework si to pretypuje automaticky.

Skus to cele rozbit na mensie kusy kodu, tj. do viacej riadkov. Bude to citatelnejsie ako ta tvoja nova implementacia.
Ale to je iba rada.

Hodne uspechov.
M.

Nahoru Odpovědět
14.8.2017 21:09
Neaktivní uživatelský účet
Avatar
zelvicek
Člen
Avatar
zelvicek:14.8.2017 22:44

K chybě samotné: nasimulovat se mi to asi nepodaří, ani jsem se o to nepokoušel. Ale z hlášky usuzuji, že chyba opravdu není přímo v tvém kódu.

Ale měl bych připomínku k metodě MapToClass. Předpokládám, že tato je volána opakovaně pro každý záznam v readeru. A pokaždé vytváříš instance entit a zjišťuješ attributy pomocí reflexe. Tento postup je značně nehospodárný. Osobně bych investoval čas do napsání metody, jež pomocí DynamicMethod zrychlí celý process.
A pokud by byl DynamicMethod příliš velký kanón, pak alespoň nějak cacheovat zjištěné metainformace o readeru a properties.

 
Nahoru Odpovědět
14.8.2017 22:44
Avatar
Luboš Běhounek Satik:15.8.2017 12:05

To spíš vypadá, že nemají aktualizovaný .NET, takže to nenajde tu knihovnu.

Nahoru Odpovědět
15.8.2017 12:05
https://www.facebook.com/peasantsandcastles/
Avatar
Odpovídá na zelvicek
Neaktivní uživatel:15.8.2017 14:08

Ahoj myslíš, že bys mohl více rozvést variantu cacheování?

Nahoru Odpovědět
15.8.2017 14:08
Neaktivní uživatelský účet
Avatar
zelvicek
Člen
Avatar
Odpovídá na Neaktivní uživatel
zelvicek:15.8.2017 18:53

No zkusme:

class Product
{
        public int Id { get; set; }
}

public void Load()
{
        using (System.Data.SqlClient.SqlDataReader dr = cmd.ExecuteReader())
        {
                MapInfo mi = GetMapInfo<Product>(dr);
                while (dr.Read())
                {
                        Product obj = MapToClass<Product>(dr, mi);
                }
        }
}

MapInfo GetMapInfo<TEntity>(System.Data.IDataReader dr) where TEntity : class,new()
{
        Type entityType = typeof(TEntity);
        return new MapInfo
        {
                Constructor = entityType.GetConstructor(Type.EmptyTypes),
                Properties = entityType.GetProperties().Select(x=> {
                        string colName;
                        MappingAttribute attribute = x.GetCustomAttributes<MappingAttribute>(true).FirstOrDefault();
                        return attribute == default(MappingAttribute) || (colName=attribute.ColumnName)!=null
                                ? null
                                : new MapPropertyInfo { PropertyInfo = x,FieldIndex=dr.GetOrdinal(attribute.ColumnName) };
                }).Where(x=>x!=null)
        };
}

static object[] _paramLess = new object[0];
TEntity MapToClass<TEntity>(System.Data.SqlClient.SqlDataReader reader, MapInfo mi) where TEntity : class, new()
{
        TEntity returnedObject = (TEntity)mi.Constructor.Invoke(_paramLess); //lepsi nez Activator.CreateInstance, jelikoz ten musi ten konstruktor taky hledat a my jej hledali jen jednou
        System.Reflection.PropertyInfo pi;
        foreach (MapPropertyInfo mpi in mi.Properties)
                (pi=mpi.PropertyInfo).SetValue(returnedObject, ChangeType(reader[mpi.FieldIndex], pi.PropertyType));
        return returnedObject;
}

class MapInfo
{
        internal System.Reflection.ConstructorInfo Constructor;
        internal IEnumerable<MapPropertyInfo> Properties;
}

class MapPropertyInfo
{
        internal System.Reflection.PropertyInfo PropertyInfo;
        internal int FieldIndex;
}

Napsal jsem to hodně horkou jehlou, nechtělo se mi s tím moc hrát. Věřím, že i přesto je záměr jasný.

Další možnost: V method Load se dá dále "MapInfo mi" cacheovat podle TEntity a cmd, tam už to nechám na tobě.

A ani teď si neodpustím doporučení na runtime kompilaci za použití DynamicMethod (vyšší dívčí) nebo Roslyn (to se vážně dá).

 
Nahoru Odpovědět
15.8.2017 18:53
Avatar
zelvicek
Člen
Avatar
Odpovídá na zelvicek
zelvicek:15.8.2017 18:58

Ještě jsem si našel chyby:

class Product
{
        [Mapping("pk")]
        public int Id { get; set; }
}

MapInfo GetMapInfo<TEntity>(System.Data.IDataReader dr) where TEntity : class,new()
{
        Type entityType = typeof(TEntity);
        return new MapInfo
        {
                Constructor = entityType.GetConstructor(Type.EmptyTypes),
                Properties = entityType.GetProperties().Select(x=> {
                        string colName;
                        MappingAttribute attribute = x.GetCustomAttributes<MappingAttribute>(true).FirstOrDefault();
                        return attribute == default(MappingAttribute) || (colName=attribute.ColumnName)!=null
                                ? null
                                : new MapPropertyInfo { PropertyInfo = x,FieldIndex=dr.GetOrdinal(attribute.ColumnName) };
                }).Where(x=>x!=null).ToArray() //bez tohohle ToArray by to byl průšvih, pročpak asi?
        };
}
 
Nahoru Odpovědět
15.8.2017 18:58
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 9 zpráv z 9.