Немного сложно создать хорошую иерархию данных в INI-файлах.Это часть того, почему MS, похоже, перешла в основном на XML-файлы.См. Ответ на этот вопрос: Чтение / запись INI-файла
Если вы выберете опцию XML, я пропущу этот процесс отображения и просто сериализую ваши объекты непосредственно после использования XPathнайти соответствующий XML.Тогда вам не нужен маппер.
Вы также можете использовать БД в памяти или на основе файлов, например SqLite .Perf будет великолепен, и у вас будет очень маленький объем развертывания.
Кроме того, я рекомендую избегать попыток абстрагировать этот маппер, так как я не думаю, что он будет хорошо транслироваться между БД и INI-файлом.,Если вы посмотрите на сложность многих библиотек ORM, то увидите, насколько сложным может быть это отображение.Большинство понятий на уровне отображения просто плохо переводятся в INI-файл.Это карты более высокого уровня, которые будут отображаться (репозитории), поэтому я разместил свой оригинальный ответ (см. Ниже).
Но если вы хотите сохранить шаблон, который вы используете, и ваш INI-файлвыглядит примерно так:
[Report.3]
IdReport = 3
IdReportRpas = 7,13
[ReportRpa.7]
IdReportRpa = 7
IdReport = 3
IdRecommendation = 12
IsDisplayed = true
Comments = I'm not sure what an RPA is...
[ReportRpa.13]
IdReportRpa = 13
IdReport = 3
; ... and rest of properties here
[Recommendation.12]
IdRecommendation = 12
IdDepartment = 33
TitleRecommendation = Some Recommendation
Description = Some Recommendation Description
DisplayOrderRecommendation = 0
[Department.33]
IdDepartment = 33
TitleDepartment = Bureau of DBs and ini files
DisplayOrderDepartment = 0
... тогда вы можете просто написать свой репозиторий, чтобы получать данные из разделов ini, и писать свои средства отображения, чтобы смотреть на каждое значение ini так же, как вы смотрите в данный момент.столбцы в наборе результатов.
using(var iniFileReader = new IniFileReader())
{
string reportSectionName = string.Format("Report.{0}", contactId);
var reportSection = iniFileReader.GetSection(reportSectionName);
// Todo: Abstract this sort of procedure/enumeration stuff out.
// Similar to the existing code's stored procedure call
int[] idReportRpas = reportSection.GetValue(IdReportRpas)
.Split(',')
.Select(s => int.Parse(s);
foreach(string idReportRpa in idReportRpas)
{
report = new CompositeEntities.ContactReportRpa();
string rpaSectionName = string.Format("ReportRpa.{0}", idReportRpa);
var rpaSection = iniFileReader.GetSection(rpaSectionName);
ContactReportRpaMapper.Map("IdReportRpa", "IdReport", "IdRecommendation",
"IsDisplayed", "Comments", report.Rpa, rpaSection);
// ...
}
}
Ваш текущий код сопоставления привязан к вашему типу хранилища, поэтому вам нужно будет придумать более общий интерфейс сопоставления.Или сделайте этот последний параметр считывателя более общим для поддержки обоих типов отображения (в вашем случае reader
, в моем случае, каждый экземпляр раздела ini).Например:
public interface IDataValueReader
{
// Signature is one that might be able to support ini files:
// string -> string; then cast
//
// As well as a DB reader:
// string -> strongly typed object
T ReadValue<T>(string valueName);
}
public class DbDataReader : IDataValueReader
{
private readonly SqlDataReader reader;
public DbDataReader(SqlDataReader reader)
{
this.reader = reader;
}
object ReadValue<T>(string fieldId)
{
return (T)reader.GetObject(reader.GetOrdinal(fieldId));
}
}
public class IniDataSectionReader : IDataValueReader
{
private readonly IniFileSection fileSection;
public IniDataSectionReader(IniFileSection fileSection)
{
this.fileSection = fileSection;
}
object ReadValue<T>(string valueName)
{
return (T)Convert.ChangeType(fileSection.GetValue(fieldId), typeof(T));
}
}
Обратите внимание, что это все пользовательский код - нет официального устройства чтения ini-файлов, и я не пробовал его, поэтому я не могу предложить, какую стороннюю библиотеку использовать., Этот вопрос, который я связал сверху , содержит несколько рекомендаций.
Оригинальный ответ
(часть его все еще может быть полезна)
Создайте interface
для своего репозитория и убедитесь, что слои более высокого уровня вашего кода общаются только с вашим хранилищем данных через этот интерфейс.
Пример интерфейса (ваш может бытьдругой):
public interface IReportRepository
{
void Create(Report report);
Report Read(int id);
void Update(Report report);
void Delete(Report report);
}
Вы также можете сделать этот интерфейс универсальным, если хотите.
Чтобы слои более высокого уровня знали только о хранилище, вы можете создать классы для разговора.к файлу / БД в реализации IReportRepository
или используйте Внедрение зависимостей для его заполнения.Но что бы вы ни делали, не сообщайте своему высокоуровневому коду о чем-либо, кроме IRepository
и ваших отдельных сущностях данных (Report
).
Возможно, вы также захотите взглянуть на ЕдиницуРабочий шаблон , и оберните фактический доступ к данным там.Таким образом, вы можете легко поддерживать транзакционную семантику и доступ к буферизированному / отложенному хранилищу (даже с файлом).
В вашем примере реализации SqlConnection
и SqlDataReader
будут жить вкласс вашей единицы работы, и код отображения и имена конкретных хранимых процедур, вероятно, будут находиться в каждом классе репозитория.
Может быть немного сложно заставить эту структуру работать полностью независимо, но если вы посмотрите накод, который генерирует Microsoft Entity Framework, фактически создает единицу рабочего класса для каждого репозитория, и вы просто получаете к нему доступ как свойство.Примерно так:
public interface IUnitOfWork : IDisposable
{
void CommitChanges();
void RollbackChanges();
}
public class MyDataModel : IUnitOfWork
{
private bool isDisposed;
private readonly SqlConnection sqlConnection;
public MyDataModel()
{
sqlConnection = DBConnection.GetConnection();
}
// Todo: Implement IUnitOfWork here
public void Dispose()
{
sqlConnection.Dispose();
isDisposed = true;
}
public IRepository<Report> Reports
{
get
{
return new ReportDbRepository(sqlConnection);
}
}
}
public class ReportDbRepository : IRepository<Report>
{
private readonly SqlConnection sqlConnection;
public ReportDbRepository(SqlConnection sqlConnection)
{
this.sqlConnection = sqlConnection;
}
// Todo: Implement IRepository<Report> here using sqlConnection
}
Полезное чтение: