Запрос Linq-to-Entities из SQL - PullRequest
       2

Запрос Linq-to-Entities из SQL

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

У меня есть EDMX с агентом, клиентом, транзакцией и формой. Агенты имеют Клиентов, у которых есть Транзакции, а Транзакции имеют формы.

Я хочу использовать проекцию, чтобы получить сразу все объекты для агента, чтобы поместить их в иерархическое древовидное представление. Древовидная структура должна отображать только транзакции и формы по выбранному году.

Мой запрос в SQL будет выглядеть примерно так:

SELECT c.*, t.*, f.* FROM Client c
INNER JOIN Client_Bucket_Client cbc on cbc.Client_GUID = c.Client_GUID
INNER JOIN Agent_Client_Bucket acb on acb.Client_Bucket_GUID = cbc.Client_Bucket_GUID
LEFT OUTER JOIN [Transaction] t on t.Client_GUID = c.Client_GUID
LEFT OUTER JOIN [Form] f on f.Transaction_GUID = t.Transaction_GUID
WHERE f.Year = 2011 AND t.Year = 2011 AND acb.Agent_GUID = 'A29B6E94-3F1B-E011-B68A-001F290A2D4A'
ORDER BY c.Last_Change_Date desc, c.File_Under

Прямо сейчас мой linq выглядит так:

var clients = from client in ObjectContext.Clients
                  join cbc in ObjectContext.Client_Bucket_Client on client.Client_GUID equals cbc.Client_GUID
                  join acb in ObjectContext.Agent_Client_Bucket on cbc.Client_Bucket_GUID equals acb.Client_Bucket_GUID
                  where acb.Agent_GUID == agentGuid
                  orderby client.Last_Change_Date descending, client.File_Under
                  select client;

    var clientInfos =
        from c in clients
        select new
        {
            Client = c,
            TransactionInfos = ObjectContext.Transactions
                .Where(t => t.Client_GUID == c.Client_GUID && t.Year == year)
                .Select(t => new
                {
                    Transaction = t,
                    ToAttach = ObjectContext.Forms.Where(f => f.Transaction_GUID == t.Transaction_GUID && f.Year == year)
                })
        };

    // Looping over this query will hit the database *once*
    foreach (var info in clientInfos)
    {
        foreach (var transactionInfo in info.TransactionInfos)
        {
            transactionInfo.Transaction.Forms.Attach(transactionInfo.ToAttach);
        }

        var tt = info.TransactionInfos.ToList(); //.Select(t => t.Transaction);

        var trans = tt.Select(t => t.Transaction);

        info.Client.Transactions.Attach(trans);
    }

    // Return a queryable object; constructing a new query from this will hit the database one more time
    return clients;

Но я получаю ошибку:

Не удалось выполнить операцию загрузки для запроса 'GetTopLevelData'. Произошла ошибка при выполнении определения команды. Смотрите внутреннее исключение для деталей. Внутреннее сообщение об исключении: истекло время ожидания. Время ожидания истекло до завершения операции или сервер не отвечает.

Вот трассировка стека:

в System.Data.EntityClient.EntityCommandDefinition.ExecuteStoreCommands (EntityCommand entityCommand, поведение CommandBehavior) в System.Data.Objects.Internal.ObjectQueryExecutionPlan.Execute [контекстная точка объекта TResultTejectObject.OtjectOject.Object.Oject.Object.Oject.Object.Oject.Object.Oject.Oject.Oject.Oject.Oject.Oject.Oject.Oject.Oject.Oject. 1.GetResults(Nullable 1 forMergeOption) в System.Data.Objects.ObjectQuery 1.System.Collections.Generic.IEnumerable<T>.GetEnumerator() at RealForms.Web.Data.RealFormsService.GetTopLevelData(Guid agentGuid, Int32 year) in C:\Users\Bryan\Documents\Visual Studio 2010\Projects\RealForms\RealForms.Web.Data\RealFormsService.cs:line 590 at GetTopLevelData(DomainService , Object[] ) at System.ServiceModel.DomainServices.Server.ReflectionDomainServiceDescriptionProvider.ReflectionDomainOperationEntry.Invoke(DomainService domainService, Object[] parameters) at System.ServiceModel.DomainServices.Server.DomainOperationEntry.Invoke(DomainService domainService, Object[] parameters, Int32& totalCount) at System.ServiceModel.DomainServices.Server.DomainService.Query(QueryDescription queryDescription, IEnumerable 1 & validationErrors, Int32 & totalCount) в System.ServiceModel.DomainServices.Hosting.QueryProcessor.Process [TEntity] (DomainService domainService, DomainOperationEntryry], DomainService domainService, DomainOperationEntry ServiceQuery serviceQuery, IEnumerable 1& validationErrors, Int32& totalCount) at System.ServiceModel.DomainServices.Hosting.QueryOperationBehavior 1.QueryOperationInvoker.InvokeCore (экземпляр объекта, входы объекта [], объект [] и выходы)

Я обнаружил, что эта ошибка возникает только на определенных данных. Кажется, что-то не так ?? 1026 *

Ответы [ 2 ]

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

Я решил мою проблему с помощью следующего кода. Я так новичок в Linq-to-Entities, я не уверен, что это лучший или предпочтительный способ сделать это, но у меня это сработало.

public IQueryable<Client> GetTopLevelData(Guid agentGuid, int year)
{
    var clients = from client in ObjectContext.Clients
                  join cbc in ObjectContext.Client_Bucket_Client on client.Client_GUID equals cbc.Client_GUID
                  join acb in ObjectContext.Agent_Client_Bucket on cbc.Client_Bucket_GUID equals acb.Client_Bucket_GUID
                  where acb.Agent_GUID == agentGuid
                  orderby client.Last_Change_Date descending, client.File_Under
                  select client;

    var clientTransactions = clients
                .Join(ObjectContext.Transactions, c => c.Client_GUID, t => t.Client_GUID,
                            (c, t) => new { Transaction = t });

    var clientForms = clientTransactions
                .Join(ObjectContext.Forms, t => t.Transaction.Transaction_GUID, f => f.Transaction_GUID,
                            (t, f) => new { Form = f });

    foreach (var client in clients)
    {
        var clientTrans = from trans in clientTransactions where trans.Transaction.Client_GUID == client.Client_GUID && trans.Transaction.Year == year select trans;
        foreach (var trans in clientTrans)
        {
            client.Transactions.Attach(trans.Transaction);

            var transForms = from forms in clientForms where forms.Form.Transaction_GUID == trans.Transaction.Transaction_GUID && forms.Form.Year == year select forms;
            foreach (var form in transForms)
            {
                trans.Transaction.Forms.Attach(form.Form);                                                             
            }
        }
    }

    return clients;
}

Я исследовал, как вкладывать объединения в Linq, но не смог заставить что-либо работать, поэтому здесь я извлекаю дочернюю транзакцию и формирую записи, а затем загружаю спроектированный клиентский объект с результатами. Я больше не получаю тайм-ауты или (Nullable1 forMergeOption) ошибки.

Спасибо всем за помощь!

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

Если вы хотите достичь JOIN в SQL, почему бы вам не использовать JOIN в LINQ?

http://msdn.microsoft.com/en-us/library/bb534675.aspx

Вот как вы можете присоединить клиентов к транзакциям:

var clientTransactions = clients
       .Join(ObjectContext.Transactions, c => c.Client_GUID, t => t.Client_GUID, 
                    (c,t) => new {Client = c, Transaction = t});

Трудно предсказать, какой запрос SQL выдаст ваш linq, поэтому я бы предпочел использовать этот синтаксис для JOIN.

P.S .: Вы получаете тайм-аут - это определенно зависит от данных, особенно от объема данных. Попробуйте выполнить профилирование запросов, которые LINQ отправляет на сервер SQL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...