2012-03-21 3 views
1

Я работаю над проектом, где нам нужно создавать сложные запросы с службой WCF.Запросить объекты DTO через WCF с linq to sql backend

Служба использует LINQ для SQL в интерфейсе и проекты запросов к объектам передачи данных, как это:

 

    dbContext.GetQueryable() 
        .Where(x => x.Id == formatId) 
        .Select(x => FormatHelper.PopulateMSFormat(x)) 
        .ToList(); 

То, что я хочу сделать, это указать запрос на стороне клиента, позволяет сказать, что я хочу запрашивать все форматы, имеющие определенное свойство, или пару из них. Что-то в стиле этого:

 

    var assets = client.QueryForAssets().Where(x => (x.name == "Test" || x == "Arne") && x.doe == "john"); 

Iam известно, что я не могу вернуться IQueryable через WCF, но что-то подобное, что может быть сделано с OData услуг. Проблема в том, что я должен вернуть DTO и OData, что позволяет мне легко привязываться к L2S-datacontext, который предоставляет мою модель данных, а не DTO.

Итак, есть хороший способ сериализации запроса против DTO, который эффективно будет распространяться на уровень l2s?

Я думал о написании собственного языка запросов, но выяснил, что построить правильное дерево выражений как предикат для l2s было бы довольно сложно, так как нет сопоставления из DTO в классы linq.

ответ

2

С услугами OData вы не обязаны напрямую возвращать объекты базы данных. Вы можете просто вернуть любой DTO в запрашиваемом формате. Затем с помощью Select() метода LINQ, вы можете просто конвертировать любой объект базы данных в DTO непосредственно перед подачей запроса:

public class DataModel 
{ 
    public DataModel() 
    { 
    using (var dbContext = new DatabaseContext()) 
    { 
     Employees = from e in dbContext.Employee 
        select new EmployeeDto 
        { 
        ID = e.EmployeeID, 
        DepartmentID = e.DepartmentID, 
        AddressID = e.AddressID, 
        FirstName = e.FirstName, 
        LastName = e.LastName, 
        StreetNumber = e.Address.StreetNumber, 
        StreetName = e.Address.StreetName 
        }; 
    } 
    } 

    /// <summary>Returns the list of employees.</summary> 
    public IQueryable<EmployeeDto> Employees { get; private set; } 
} 

Теперь вы можете легко установить это как служба OData, как это:

public class EmployeeDataService : DataService<DataModel> 

Для полной информации об осуществлении, see this отличная статья на эту тему. Услуги OData на самом деле очень мощные, когда вы получаете их.

+0

Это звучит неплохо, но я не могу заставить его работать. Подозреваю, что это связано с тем, что я использую L2S, а не EF –

+0

Найден как минимум две проблемы. Я не могу использовать вспомогательный метод, и поскольку контекст завернут в его использование, он будет удален при запросе коллекции. –

+0

Использование L2S или EF не имеет значения. Вы можете объединить данные из любого источника. Поскольку объекты службы OData создаются «за запрос», правильное использование оператора 'using' является правильным, так как экземпляр класса DataModel будет создан и уничтожен вместе с запросом. –

0

Я считаю, что вы можете вернуть DTO с помощью служб OData.

Посмотрите на http://www.codeproject.com/Articles/135490/Advanced-using-OData-in-NET-WCF-Data-Services. В частности, раздел «Выявление трансформации вашей базы данных». Вы можете сгладить объекты сущности в DTO и попросить клиента выполнить запросы против этой модели DTO.

Это что-то, что вы ищете?

0

Если у вас есть длинные сложные сущности, то создание проекции вручную - это кошмар. Automapper не работает, потому что LINQ не может использовать его в сочетании с IQueryable.

Это здесь является идеальным решением: Stop using AutoMapper in your Data Access Code

Он будет генерировать проекцию «волшебным» для вас и дать вам возможность выполнить запрос OData на основе вашего DTO (данные объекта передачи) класса.

[Queryable] 
    public IQueryable<DatabaseProductDTO> GetDatabaseProductDTO(ODataQueryOptions<DatabaseProductDTO> options) 
    { 
     // _db.DatabaseProducts is an EF table 
     // DatabaseProductDTO is my DTO object 
     var projectedDTOs = _db.DatabaseProducts.Project().To<DatabaseProductDTO>(); 

     var settings = new ODataQuerySettings(); 
     var results = (IQueryable<DatabaseProductDTO>) options.ApplyTo(projectedDTOs, settings); 

     return results.ToArray().AsQueryable(); 
    } 

Я бегу это с

/odata/DatabaseProductDTO?$filter=FreeShipping eq true 

. Примечание: эта статья от несколько лет назад, и вполне возможно, что теперь AutoMapper имеет функциональность, как это встроенный в меня просто не хватает времени, я проверьте это прямо сейчас. Вдохновение для указанной выше статьи было основано на this article автором самого AutoMapper - так что теперь возможно усовершенствованная версия. Общая концепция кажется отличной, и эта версия работает хорошо для меня.

Смежные вопросы