Предоставление бизнес-уровня LinqToSQL через службу данных WCF - PullRequest
2 голосов
/ 06 июля 2010

Я ищу способ раскрыть подмножество моего существующего бизнес-уровня (основанного на LinqToSql) через службы данных WCF, чтобы

  1. Служба данных все еще может использоваться (считывать и записывать) старыми клиентами odata, так как мой бизнес-уровень со временем развивается. Кажется, что единственный способ гарантировать это - убедиться, что служба данных не меняется, даже если меняется бизнес-уровень.

  2. Некоторые свойства моих бизнес-объектов скрыты.

  3. Служба данных может обрабатывать относительно большие базы данных (десятки тысяч субъектов бизнеса)

  4. У меня не займет несколько недель, чтобы внедрить службу данных

Я пробовал несколько разных подходов, но у каждого из них есть существенные недостатки. Будем весьма благодарны за любые указания по поводу вещей, которые я упустил.

Вот те подходы, которые я пробовал до сих пор:

Первый подход: поставщик на основе отражений, реализующий IUpdateable, бизнес-объекты, реализующие четко определенный интерфейс

Вместо того, чтобы выставлять мои объекты LinqToSQL напрямую, я пытался заставить их реализовать интерфейс, который определяет свойства, которые я хочу показывать, и выставлять только этот интерфейс в службе данных. Например, если у меня есть сущность Customer linq, я должен реализовать интерфейс ICustomer:

public interface ICustomer{
   int ID{get;set;}
   string Name{get;set;}
}


//My Linq entity 
public partial class Customer: ICustomer{
   public int ID{get;set;}
   public string Name{get;set;}
   public string SomeOtherPropertyIDoNotWantToExpose{get;set;}
}

Затем в моем провайдере данных я просто помещаю свойство, как

public IQueryable<ICustomer> Customers    {
      get { 
        //Note that the method below returns an IQueryable<Customer>
        return MyBusinessLayerCustomersProvider.LoadAllCustomers();
      }
    }

К сожалению, это не работает. При попытке получить доступ к службе данных со стороны клиента и использовать любой метод Linq, основанный на OrderBy (например, myContext.Customers.First ()), я получаю следующую ошибку:

Никакой универсальный метод 'OrderBy' для типа 'System.Linq.Queryable' не совместим с предоставленными аргументами и аргументами типа. Аргументы типа не должны предоставляться, если метод не является универсальным.

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

Второй подход: поставщик на основе отражений, реализующий IUpdateable, класс-оболочку для моих существующих объектов

В этом случае я попытался реализовать классы вокруг моих сущностей linq и предоставить класс-оболочку службе данных. Что-то вроде:

  //My Linq entity 
  public partial class Customer 
  {
    public int ID { get; set; }
    public string Name { get; set; }
    public string SomeOtherPropertyIDoNotWantToExpose { get; set; }
  }

  //the wrapper
  public partial class WrappedCustomer
  {
    internal Customer _wrappedEntity;
    public int ID { get{ return _wrappedEntity.ID;} set{ _wrappedEntity.ID = value;} }
    public string Name { get { return _wrappedEntity.Name; } set { _wrappedEntity.Name = value; } }
  }

Проблема этого подхода заключается в том, что он не работает, если я не загружаю все объекты Customer из моей базы данных в память при каждом запросе к службе данных. Это связано с тем, что свойство Customers в поставщике службы данных выглядит следующим образом:

public IQueryable<Customer> WrappedCustomer
{
  get
  {
    IQueryable<WrappedCustomer> customers = from c in MyBusinessLayerCustomersProvider.LoadAllCustomers
                 select new WrappedCustomer{_wrappedEntity = c};

    //I am casting to list to avoid "no supported translation to sql" errors. 
    return tasks.ToList().AsQueryable();
  }
}

Таким образом, даже если размер страницы для моей службы данных wcf ограничен 100, приведенный выше код загрузит ВСЕ объекты клиентов в память, прежде чем он сможет найти нужные объекты, которые клиент действительно хочет загрузить. Так что, похоже, это неправильно масштабируется.

Третий подход: напрямую открывать сущности LinqToSQL, использовать атрибут IgnoreProperties

В этом случае я хотел бы, чтобы моя служба данных возвращала сущности linqtosql, происходящие непосредственно из моего бизнес-уровня, и использовала атрибут IgnoreProperties, чтобы скрыть свойства, которые я не хочу показывать на уровне данных. Этот подход масштабируется и его легко реализовать, но он не поддерживает правильное управление версиями службы данных. Например, если я хочу реализовать версию 2 своего сервиса данных, мне может потребоваться скрыть меньше свойств сущности linq, чем в первом сервисе. и, похоже, нет способа использовать несколько атрибутов IgnoreProperties для одного объекта LinqToSQL.

Четвертый подход: реализация специализированного поставщика услуг передачи данных

Кажется, что провайдеры пользовательских данных могут легко удовлетворить все мои требования. Теперь это может быть только я, но это выглядит слишком сложно. Кажется, я должен реализовать IDataServiceMetadataProvider, IDataServiceQueryProvider, IDataServiceUpdateProvider и IServiceProvider, ни один из которых не является тривиальным. И даже после прочтения серии статей Алекса J на эту тему и изучения примера, представленного на веб-сайте odata, я все еще не понимаю, что на самом деле выполняет большинство функций, которые мне нужно реализовать.

Кажется, намного сложнее, чем просто реализовать IUpdateable, тем более что я не знаю, какие части кода, представленные в примерах, можно просто скопировать и вставить или их нужно настроить.

Пятый подход: используйте EF и найдите способ заставить бизнес-уровень работать как с Linq to SQL, так и с EF

Мне удалось реализовать для этого концептуальное доказательство, но оно довольно грязное, поэтому я бы использовал это только в качестве крайней меры.

Итак, что я упустил? Что я должен делать дальше? У меня не хватает времени, поэтому любые советы будут с благодарностью.

Спасибо

Адриан

1 Ответ

1 голос
/ 07 июля 2010

Похоже, что единственный способ удовлетворить все мои требования - внедрить пользовательский поставщик услуг передачи данных ( см. Эту ветку ).Это не маленькая задача, поэтому я решил пока использовать реализацию поставщика отражения + IUpdateable и внедрить пользовательский поставщик услуг передачи данных, если необходимость возникнет позже (из-за проблем с версиями).

...