Как выполнить операцию соединения на стороне службы в службах данных WCF - PullRequest
0 голосов
/ 24 февраля 2011

Я знаю, что "join" не поддерживается на стороне клиента с WCF DS, поэтому я решил добавить метод на стороне сервера, чтобы выполнить "join" и вернуть результат как объект пользовательского типа.Служба выглядит следующим образом:

 public class CWcfDataService : DataService<CEntities>
    {
        // This method is called only once to initialize service-wide policies.
        public static void InitializeService(DataServiceConfiguration config)
        {
            config.UseVerboseErrors = true;
            config.RegisterKnownType(typeof(CASE_STAGE_HISTORY_EXTENDED));
            config.SetEntitySetAccessRule("*", EntitySetRights.All);
            config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
            config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
        }

        [WebGet]
        public IQueryable<CASE_STAGE_HISTORY_EXTENDED> GetCASE_STAGE_HISTORY_EXTENDEDByDocId(int docId)
        {
            CEntities context = new CEntities();
            return (from c in context.CASE_STAGE_HISTORY
                    join a in context.USRs on c.CREATOR_ID equals a.USRID
                    select new CASE_STAGE_HISTORY_EXTENDED()
                    {
                        CASE_STAGE_ID = c.CASE_STAGE_HISTORY_ID,
                        CASE_STAGE_NAME = c.CASE_STAGE_NAME,
                        CREATE_DATE = c.CREATE_DATE,
                        CREATOR_ID = c.CREATOR_ID,
                        DOC_ID = c.DOC_ID,
                        LAST_VARIANT_DOCUMENT_ID = c.LAST_VARIANT_DOCUEMENT_ID,
                        CREATOR_FULLNAME = a.FULLNAME
                    });
        }    
    }

И пользовательский класс:

   [DataServiceKey("CASE_STAGE_ID")]
    public class CASE_STAGE_HISTORY_EXTENDED
    {
        public int CASE_STAGE_ID { get; set; }
        public int DOC_ID { get; set; }
        public string CASE_STAGE_NAME { get; set; }
        public int? LAST_VARIANT_DOCUMENT_ID { get; set; }
        public DateTime? CREATE_DATE { get; set; }
        public int? CREATOR_ID { get; set; }
        public string CREATOR_FULLNAME { get; set; }
    }

Когда я пытаюсь обновить ссылку на службу в Visual Studio, я постоянно получаю сообщение об ошибке:

Сервер обнаружил ошибку при обработке запроса.Сообщение об исключении: «Невозможно загрузить метаданные для возвращаемого типа» System.Linq.IQueryable 1[CWcf.Code.CASE_STAGE_HISTORY_EXTENDED]' of method 'System.Linq.IQueryable 1 [CWcf.Code.CASE_STAGE_HISTORY_EXTENDED] GetCASE_STAGE_HISTORY_EXTENDEDByDocId (Int32) '.'.Дополнительные сведения см. В журналах сервера.

Если я удаляю часть public IQueryable<CASE_STAGE_HISTORY_EXTENDED> GetCASE_STAGE_HISTORY_EXTENDEDByDocId(int docId) - при обновлении справочной службы я получаю еще одну ошибку:

Сервер обнаружил ошибку при обработкезапрос.Сообщение об исключении: «Внутренняя ошибка сервера.Тип 'CourtWcf.Code.CASE_STAGE_HISTORY_EXTENDED' не является сложным типом или типом сущности. '.

Среда : Visual Studio 2010, .NET 4.

Ответы [ 3 ]

0 голосов
/ 25 февраля 2011

Я предполагаю, что служба данных основана на модели Entity Framework (класс CEntities является ObjectContext).В этом случае типы полностью считываются из модели EF (CSDL), а определения классов более или менее игнорируются.Таким образом, вам нужно определить тип, возвращаемый вашей сервисной операцией в вашей модели EF.Также обратите внимание, что для работы IQueryable этот тип должен быть распознан EF как тип сущности (что может потребовать сопоставления с базой данных или чем-то еще, эксперты EF узнают больше).

0 голосов
/ 01 марта 2011

Добавлены внешние ключи и реализован LoadProperty. Смотрите статью, из которой я взял это решение: http://thedatafarm.com/blog/data-access/the-cost-of-eager-loading-in-entity-framework/ Тем не менее, если у меня НЕТ отношений в базе данных (например, у меня нет внешних ключей) - у меня есть другое решение: создать хранимую процедуру и сопоставить ее с импортом в вашей модели БД. После этого создайте сложный тип, который будет работать и в клиенте (однако вам придется обращаться к нему по URI, а не с лямбда-расширениями). См. Пример здесь .
Большое спасибо за другие ответы в этой теме, вы заставили меня глубже вникнуть в тему.

0 голосов
/ 24 февраля 2011

Для начала WCF не поддерживает IQueryable. Вот твоя проблема.

В вашем случае IEnumerable должен работать.

Вы должны смотреть на сервис как на то, что имеет методы и возвращает «данные». Эти данные могут быть отдельными значениями, экземплярами объектов или коллекциями объектов. Клиенту не нужно думать о том, чтобы позвонить в службу, чтобы выполнить соединение, а, скорее, «дать мне данные для того и того - с учетом этих параметров».

Имя вашего метода передает правильный "intent" GetCaseStageHistoryExtendedByDocId (int docId), и вы получаете обратно коллекцию объектов CASE_STAGE_HISTORY_EXTENDED. Вот и все.

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

EDIT

Попробуйте преобразовать Queryable в List, вызвав для него метод ToList ().

возврат (из контекста c. CASE_STAGE_HISTORY присоединиться к in context.USR на c.CREATOR_ID равно a.USRID выберите новый CASE_STAGE_HISTORY_EXTENDED () { CASE_STAGE_ID = c.CASE_STAGE_HISTORY_ID, CASE_STAGE_NAME = c.CASE_STAGE_NAME, CREATE_DATE = c.CREATE_DATE, CREATOR_ID = c.CREATOR_ID, DOC_ID = c.DOC_ID, LAST_VARIANT_DOCUMENT_ID = c.LAST_VARIANT_DOCUEMENT_ID, CREATOR_FULLNAME = a.FULLNAME }) ToList ();.

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

...