Игорь! разъясни, пожалуйста, генеральную политику партии в отношении вложенных классов.
Во всему выходит, что
этоАвтор(ы): Игорь Ткачёв
Дата: 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>>