Вопрос по вложенным классам
От: Блудов Павел Россия  
Дата: 26.05.06 07:40
Оценка:
Игорь! разъясни, пожалуйста, генеральную политику партии в отношении вложенных классов.

Во всему выходит, что это
Автор(ы): Игорь Ткачёв
Дата: 01.07.2003
В статье подробно рассматривается состав и способы применения пространства имён Rsdn.Framework.Data, представляющего собой высокоуровневую обёртку над ADO.NET.
единственное, что с ними можно делать.

Вот такой тест совсем-совсем не работает:
public abstract class RecordHeader : EditableObject
{
    [MaxLength(50), Required]
    public abstract string Last { get; set; }
    [MaxLength(50), Required]
    public abstract string First { get; set; }
    [MaxLength(50), NullValue("")]
    public abstract string Middle { get; set; }
}

[TableName("Person")]
public abstract class Person : EditableObject
{
    [Required]                     public abstract Gender Gender     { get; set; }
    [MapIgnore(false)]
    public abstract RecordHeader Name { get; set; }
    [PrimaryKey, NonUpdatable]
    [MapField("PersonID")]         public abstract int    ID         { get; set; }
}

public abstract class PersonAccessor : DataAccessor
{
    public abstract Person SelectByName(Person p);
}

[Test]
public void SelectByNameTest()
{
    Person e = TypeAccessor.CreateInstance<Person>();
    e.Name.First = "John";
    e.Name.Last = "Pupkin";

    Person p = _da.SelectByName(e);
    Assert.AreEqual(1, p.ID);
}
Срубается из-за того, что в DbManager.CreateParameters() отсутствуют выделенные жирным строки:
public IDbDataParameter[] CreateParameters(object obj, params IDbDataParameter[] commandParameters)
        {
            ArrayList    paramList = new ArrayList();
            ObjectMapper om        = _mappingSchema.GetObjectMapper(obj.GetType());

            foreach (MemberMapper mm in om)
            {
                Type type = mm.Type;
                object value = mm.GetValue(obj);

                if (TypeHelper.IsScalar(type))
                {
                    string name  = _dataProvider.Convert(mm.Name, ConvertType.NameToParameter).ToString();

                    paramList.Add(mm.MapMemberInfo.Nullable || value == null?
                        NullParameter(name, value, mm.MapMemberInfo.NullValue):
                        Parameter    (name, value));
                }
                else
                {
                    paramList.AddRange(CreateParameters(value));
                }
            }

            if (commandParameters != null)
                foreach (IDbDataParameter p in commandParameters)
                    paramList.Add(p);

            return (IDbDataParameter[])paramList.ToArray(typeof(IDbDataParameter));
        }

Так вот, основная проблема в том, какие же имена давать таким параметрам? Вариантов два: типа Name.First и просто First.
Второе мне нравится больше, так как объекты типа:
        public abstract class RecordHeader
{
    public abstract string Name { get; set; }
}

public abstract class Person : EditableObject
{
    public abstract RecordHeader Header { get; set; }
    public abstract string Name { get; set; }
}
выглядят как попытка наступить на грабли в самом ближайшем будущем.
Кроме того, MSSQL не понимает имён параметров типа @Name.First Максимум, на что он согласен это @Name_First.

Давайте мапить поля вложенных классов без префикса, а кому очень нужно, пусть задают его явно.
Для этого нужно всего лишь избавиться от хака с GetComplexMapper.
Вместо него всегда брать и добавлять мапперов вложенных классов во внешние классы через ComplexMapper с тем же именем. Т.е. в ObjectMapper'е:

protected virtual MemberMapper CreateComplexMapper(MemberMapper mm, MemberAccessor ma)
{
    MapMemberInfo cmi = new MapMemberInfo();

    cmi.MemberAccessor = ma;
    cmi.Type = mm.Type;
    cmi.MappingSchema = mm.MappingSchema;
    cmi.Name = mm.Name;
    cmi.MemberName = mm.MemberName;

    MemberMapper mapper = new MemberMapper.ComplexMapper(mm);

    mapper.Init(cmi);

    return mapper;
}

public virtual void Init(MappingSchema mappingSchema, Type type)
{
    if (type == null) throw new ArgumentNullException("type");

    _typeAccessor  = TypeAccessor.GetAccessor(type);
    _mappingSchema = mappingSchema;
    _extension     = TypeExtension.GetTypeExtenstion(
        _typeAccessor.OriginalType, mappingSchema.Extensions);

    foreach (MemberAccessor ma in _typeAccessor)
    {
        if (GetIgnore(ma))
            continue;

        MapMemberInfo mi = new MapMemberInfo();

        mi.MemberAccessor  = ma;
        mi.Type            = ma.Type;
        mi.MappingSchema   = mappingSchema;
        mi.MemberExtension = _extension[ma.Name];
        mi.Name            = GetFieldName   (ma);
        mi.MemberName      = ma.Name;
        mi.Trimmable       = GetTrimmable   (ma);
        mi.MapValues       = GetMapValues   (ma);
        mi.DefaultValue    = GetDefaultValue(ma);
        mi.Nullable        = GetNullable    (ma);
        mi.NullValue       = GetNullValue   (ma, mi.Nullable);

        Add(CreateMemberMapper(mi));

        if (!TypeHelper.IsScalar(ma.Type))
        {
            ObjectMapper com = Map.GetObjectMapper(ma.Type);
            foreach (MemberMapper cmm in com)
            {
                Add(CreateComplexMapper(cmm, ma));
            }
        }
    }

    /* А это выкинуть за ненадобностью. А можно и оставить, чтобы и First и Name.First работали.
    foreach (AttributeExtension ae in _extension.Attributes["MapField"])
    {
        string mapName  = (string)ae["MapName"];
        string origName = (string)ae["OrigName"];

        if (mapName == null || origName == null)
            throw new MappingException(string.Format(
                "Type '{0}' has invalid  extension. MapField MapName='{1}' OrigName='{2}'.",
                    type.FullName, mapName, origName));

        EnsureMapper(mapName, origName);
    }

    foreach (MapFieldAttribute attr in MapFieldAttributes)
        EnsureMapper(attr.MapName, attr.OrigName);
    */
}


Тормозов это не прибавит, кроме экзотического случая, когда вложенный класс заявлен для мапинга, но на деле не используется.
Если вложенных классов нет — то нет и тормозов.

P.S. Игорь, если ты не против, но сильно занят, то гони ключи от квартиры, буду сам переделывать.
... << RSDN@Home 1.2.0 alpha rev. 642>>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.