Re[20]: Несколько вопросов по Меппарам.
От: GlebZ Россия  
Дата: 20.05.05 15:42
Оценка: 3 (1)
Здравствуйте, igor_fle, Вы писали:

Наконец руки дошли.
Что-то мне это не сильно нравится все это. Кому-то надо, кому-то не надо. Если нельзя объединять усилия по достижению общей цели, то менеджеров к стенке надо ставить. (или в сортире мочить как учит одно небезызвестное лицо) . Унифицировать интерфейсы(и состояние бизнес объектов) архиважная задача на пути к коммунизму и снижения издержек при буржуазном строе. Решить это политически значительно дешевле чем реализацию(с постановкой и тестированием). Это по количеству данных(состоянию) в возвращаемом объекте. Что касается самих объектов, то тот кому нужны адреса, должен заказывать адреса. Тому кому нужно companies тот заказывает companies. Это нормально.

Теперь по решению.
Самое простое решение описанное во все книжках. Каждый заказывает то что ему нужно. То бишь:
interface MyInterface{
GetCompany(id);
GetAdress(companyId);
GetCompanyFinancialDetails(id);
}

Каждый берет столько сколько нужно. Правда маленький недостаток. Оверхед количества вызовов. Проверено на практике, что кроме криминальных случаев, некоторый оверхед по объему дешевле чем оверхед по количеству вызовов. Поэтому дополнительно предлагаю следующий вариант.
Клиент:
Finder finderCompany=new Finder();
finderCompany.ObjectName="Company";//имя заказываемого объекта
finder.AddEqualPredicate("id", 1000);//получить те объекты у которого поле id=1000
Finder finderAddress=new Finder();
finderAddress.ObjectName="Address";
finderCompany.AddJoin(finderAddress, "AddressId", "Id");//добавляем связку показывающую что также нужны адреса.
server.GetCompanies(finder);

На сервере. Тут нужно всегда знать что если работаешь c layer'ами, изволь ими пользоваться. Поэтому тут задача передать заказ из внешнего слоя в нижний решается с помощью сервиса(если конечно это не Domain Model), допустим это объект ObjectGetter.
public DTO MyInterface.GetObjects(Finder finder)
{
  IList companies=ObjectGetter.GetByFinders(finder);
    return FormatDTO.FormatDTOFromObjects(companies);//форматируем в формат протокола пересылки бизнес объектов
}
//здесь у нас описывается запрос уже в терминах SQL.
public struct SelectDescription
{
    string _selectFields;//строка для селектов
    string _from;//строка для from (но без joins)
    string _predicates; // строка для where
    Join[] _joins;//описываем с кем связаны
    string _alias;//алиас таблицы в запросе для данного маппера
    IMapper _mapper; //ссылка на того, кто будет собирать результаты из него
}
//отдельно описываем джоины
public struct Join
{
  string _predicate;//предикат связываения
    EnumTypeJoin _typeJoin;//по какому joinу (внешний, внутренний)
    SelectDescription _joinedDescription;//кого приджоиним
}

//само получение данных
public IList ObjectGetter.GetByFinder(Finder finder)
{
  SelectDescription selectDescriptor=GenerateDescriptor(finder);
    //из полученных данных генерируем запрос
    string sqlSelect=GenerateCommandString(selectDescription);
    ArrayList result=new ArrayList();
    //естественно, если нужна независимость от базы данных, или транзакции то операции БД в отдельные классы
    using (SqlConnection connection=new SqlConnection(connectionString))
    {
        myConnection.Open();
        using(SqlDataReader myReader = new SqlCommand(sqlSelect, myConnection).ExecuteReader(CommandBehavior.CloseConnection))
        {
            while(myReader.Read()) 
            {
                ReadFromReader(result, myReader, selectDescription);
            }
            myReader.Close();
        }
    }
    return result;
}


//заполняем структуру SelectDescription уже SQL данными 
public SelectDescription ObjectGetter.GenerateDesciptor()
{
    //обязательно пытаемся делать через маппер для конретного типа.
    //Тогда мы можем управлять поведением заполнения и языка запросов
    //в случае наличия универсального хранилища метаданных(и следовательно управления языком запросов)
    // это можно сделать через один объект
    IMapper mapper=GetMapperByObjectName(finder.ObjectName);
    //создаем дескриптор для построение select 
    //второй параметр важен. алиас должен быть уникальным.
    SelectDescription descriptor=mapper.GetSelectDescription(mapper, GenerateAlias());
    //рекурсивно делаем joins
    foreach(Finder finderJoined in finder.Joins)
    {
        SelectDescription joinedDescriptor=ObjectGetter.GenerateDescriptor(finder, GenerateAlias());
        AppendJoin(desciption, joinedDescription);//заполняем структуры Join
    }
    return descriptor;
}
//чтение объекта из строки
public void ReadFromReader(ArrayList arrayResult, SqlDataReader myReader, SelectDescription descriptor)
{
    //создают и заполняют объекты безусловно мапперы
  descriptor.Mapper.LoadObjects(arrayResult, description, myReader);
    //заполняем по рекурсии joins
    foreach (Join join in descriptor.Joins)
        ReadFromReader(arrayResult, myReader, join.SelectDescriptor);
    return arrayResult;
}

Код написан только примерно и сходу. Поэтому там должно быть множество ошибок (я так думаю). Просто описано достаточно, чтобы понять само решение. Result может быть (а обычно бывает) не просто ArrayList, а более сложным.

С уважением, Gleb.
... << RSDN@Home 1.1.4 beta 4 rev. 358>>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.