Я ищу способ раскрыть подмножество моего существующего бизнес-уровня (основанного на LinqToSql) через службы данных WCF, чтобы
Служба данных все еще может использоваться (считывать и записывать) старыми клиентами odata, так как мой бизнес-уровень со временем развивается. Кажется, что единственный способ гарантировать это - убедиться, что служба данных не меняется, даже если меняется бизнес-уровень.
Некоторые свойства моих бизнес-объектов скрыты.
Служба данных может обрабатывать относительно большие базы данных (десятки тысяч субъектов бизнеса)
- У меня не займет несколько недель, чтобы внедрить службу данных
Я пробовал несколько разных подходов, но у каждого из них есть существенные недостатки. Будем весьма благодарны за любые указания по поводу вещей, которые я упустил.
Вот те подходы, которые я пробовал до сих пор:
Первый подход: поставщик на основе отражений, реализующий 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
Мне удалось реализовать для этого концептуальное доказательство, но оно довольно грязное, поэтому я бы использовал это только в качестве крайней меры.
Итак, что я упустил? Что я должен делать дальше? У меня не хватает времени, поэтому любые советы будут с благодарностью.
Спасибо
Адриан