Классы сущностей развязаны от поставщика LINQ to SQL для реализации шаблона Repository. Как? - PullRequest
9 голосов
/ 23 октября 2008

Я просмотрел шаблон репозитория и узнал некоторые идеи, которые использовал в прошлом, и это заставило меня чувствовать себя хорошо.

Однако теперь я хотел бы написать приложение, которое будет использовать этот шаблон Но я бы хотел, чтобы классы объектов были отключены от поставщика хранилища.

Я бы создал несколько сборок:

  1. сборка «Интерфейсы», в которой будут размещаться общие интерфейсы, включая интерфейс IRepository
  2. сборка «Сущности», в которой будут размещаться такие классы сущностей, как Product, User, Order и т. Д. На эту сборку будет ссылаться сборка «Интерфейсы», поскольку некоторые методы будут возвращать такие типы или их массивы. Также на него будет ссылаться основная сборка приложения (например, веб-приложение)
  3. одна или несколько сборок / сборок поставщика репозитория. Каждый из них будет включать (по крайней мере) класс, который реализует интерфейс IRepository, и он будет работать с определенным хранилищем данных. Хранилища данных могут включать SQL Server, сервер Oracle, MySQL, файлы XML, службы Web / WCF и т. Д.

Изучение LINQ to SQL, которое выглядит очень продуктивно с точки зрения времени, затрачиваемого на реализацию всего, кажется хорошим, пока я не обнаружу глубокую зависимость между сгенерированными классами и классом CustomDataContext.

Как я могу использовать LINQ to SQL в таком сценарии?

Ответы [ 9 ]

6 голосов
/ 23 октября 2008

Я не знаю, является ли это именно тем, что вам нужно, но вы можете взглянуть на код MVC Магазина Роба Конери. Он использует вариант шаблона хранилища с поставщиком linq. Он сопоставляет объекты LINQ to Sql с объектами домена, а затем возвращает объекты домена от поставщика хранилища на уровень обслуживания, который оборачивает поставщика, позволяя ему проработать некоторую логику с данными, возвращаемыми до того, как они попадут на бизнес-уровень.

Веб-трансляции с MVC Storefront
код

Для меня это звучит так, как будто вы хотите, чтобы провайдеры возвращали DTO, а затем вы хотите сопоставить DTO с объектами домена на уровне хранилища / службы. В этом случае вы можете сопоставить ваш поставщик LINQ to SQL с DTO, сделать так, чтобы он возвращал их, а затем сопоставить DTO с объектами домена на уровне хранилища / службы. Это должно работать просто отлично, но это может стать утомительным, так как теперь у вас будет 2 слоя отображения.

В этом случае вы бы имели: ProductService, который принимает IProductRepository. Он вызывает методы в IProductRepository для возврата ваших DTO. Затем он сопоставляет DTO с реальными бизнес-объектами и возвращает их в вызывающий код.

5 голосов
/ 24 октября 2008

Вы можете создать внешний XML-файл, отображающий базу данных в любой класс:

 <?xml version="1.0" encoding="utf-8"?>
 <Database Name="DbName" 
           xmlns="http://schemas.microsoft.com/linqtosql/dbml/2007">
    <Table Name="DbTableName">
       <Type Name="EntityClassName" >
           <Column Name="ID" Type="System.Int64" Member="Id"
                   DbType="BigInt NOT NULL IDENTITY" IsPrimaryKey="true"
                   CanBeNull="false" />
           <Column Name="ColumnName" Type="System.String" Member="PropertyA"
                   DbType="VarChar(1024)" CanBeNull="true" />
       </Type>
    </Table>
 </Database>

А затем передать XML в класс DataContext:

 using (var cn = GetDbConnection())
  { var mappingSrc = XmlMappingSource.FromReader(xmlReader);

    using (var db = new DataContext(cn, mappingSrc))
     { var q = from entity in db.GetTable<EntityClassName>()
               where entity.PropertyA = "..."
               select entity.ID;
     }
  }
4 голосов
/ 12 апреля 2009

Я нашел фантастическое сообщение в блоге (с большим количеством хорошего кода) об этом здесь: http://iridescence.no/post/Linq-to-Sql-Programming-Against-an-Interface-and-the-Repository-Pattern.aspx

3 голосов
/ 24 октября 2008

Думаю, вам нужна поддержка POCO (Plain Old CLR Objects). LINQ to SQL имеет адаптер под названием Close2Poco .

Но я бы посоветовал перейти на Entity Framework, на данный момент у них также есть POCO-адаптер , но в v2 ожидается, что он будет поддерживаться из коробки .

2 голосов
/ 24 октября 2008

Я сделал что-то похожее с WCF

1 В вашем DBML установите режим сериализации на Однонаправленный

2 Установите для ВСЕХ столбцов в ваших таблицах значение UpdateCheck = false

3 Напишите свой сервис примерно так:

<pre> public class Service1 : IService1 { public Company GetCompany(int companyId) { using (DataClasses1DataContext dc = new DataClasses1DataContext()) { return (from c in dc.Companies where c.CompanyId == companyId select c).Single(); } }</p> <pre><code> public void SaveCompany(Company company) { using (DataClasses1DataContext dc = new DataClasses1DataContext()) { dc.Companies.Attach(company, true); dc.SubmitChanges(); } } public void InsertCompany(Company company) { using (DataClasses1DataContext dc = new DataClasses1DataContext()) { dc.Companies.InsertOnSubmit(company); dc.SubmitChanges(); } } }

4 Добавить сервисную ссылку

2 голосов
/ 24 октября 2008

Простейшим способом было бы отделить ваши сущности от datacontext: загрузить нужную сущность, отделить ее от DataContext, использовать ее так, как вам нравится, позже использовать Attach (), чтобы связать ее с DataContext для сохранения.

К сожалению, у LINQ нет способа отделить сущности от текста данных, но вы можете просто их клонировать, что прекрасно работает. Проще всего было бы что-то вроде этого:

public static T CloneEntity<T>(T source)
{
  DataContractSerializer dcs = new DataContractSerializer(typeof(T));
  using (Stream stream = new MemoryStream())
  {
    dcs.WriteObject(stream, source);
    stream.Seek(0, SeekOrigin.Begin);
    return (T)dcs.ReadObject(stream);
  }
}
2 голосов
/ 24 октября 2008

Вам не нужно использовать сгенерированный код LINQ to SQL, вы можете украсить свои собственные классы необходимыми атрибутами ColumnAttributes или использовать внешний файл сопоставления XML.

1 голос
/ 23 октября 2008

Могут ли ваши классы сущностей реализовать интерфейсы IProduct, IUser, IOrder и т. Д., Которые будут объявлены в вашей сборке "Интерфейсы"? Таким образом, интерфейс IRepository ссылается только на интерфейсы бизнес-объектов (т. Е. Возвращает коллекции IProduct и т. Д.), И сборка «Интерфейсы» отделена от других сборок, специфичных для реализации.

1 голос
/ 23 октября 2008

Не совсем тот же сценарий, но я работаю над созданием специального инструмента, который на основе XML-файла будет генерировать ОО-модель. Мой подход заключается в использовании LINQ to SQL за кулисами, и, поскольку я генерирую код автоматически, было бы легко использовать другой механизм, скажем, для источника данных MySQL. Поскольку он не поддерживается LINQ to SQL, вам придется писать код доступа к данным вручную, но код клиента, который будет использовать модель OO, изменится любым образом.

...