Fórum Usar stored procedures com Linq to Entities #9501

23/09/2009

0

Oi!

Gostaria de saber com vocês como faço para utilizar stored procedures no linq to entities. Eu tenho um data model que foi gerado por meio do wizard de importação apontando para um banco de dados com algumas stored procedures.

Após importar, não consegui localizar as stored procedures da mesma forma que visualizo as tabelas no design. Numa pesquisa no google, eu encontrei um post que você precisa adicionar um "Function Import". Eu fiz isso, selecionei a stored procedure e dei um nome para ela no meu context.

Porém, após instanciar meu context e tentar utilizar ela, a mesma não, aparece, somente as tabelas mesmo.

Tem alguma coisa a mais que preciso fazer ou que fiz errado para poder usar a stored procedure com linq to entities?

Fico no aguardo, obrigado pela atenção!

Atenciosamente,

Carlos
Carlos Nogueira

Carlos Nogueira

Responder

Posts

23/09/2009

Luiz Maia

Ola Carlos,   Esta SP precisa ser mapeada para que se torne uma entidade. Siga os passos abaixo, no exemplo esta sendo usado o Banco AdventureWorks, gratuito da Microsoft.   Criação da Porcedure:   USE AdventureWorks; GO IF OBJECT_ID ( 'dbo.GetOrderDetails', 'P' ) IS NOT NULL     DROP PROCEDURE dbo.GetOrderDetails; GO   CREATE PROCEDURE dbo.GetOrderDetails    @SalesOrderHeaderId int AS     SELECT SalesOrderID, SalesOrderDetailID, CarrierTrackingNumber,             OrderQty, ProductID, SpecialOfferID, UnitPrice, UnitPriceDiscount,             rowguid, ModifiedDate     FROM Sales.SalesOrderDetail WHERE SalesOrderID = @SalesOrderHeaderId; GO Função que deve ser criada no arquivo .edmx no SSDL:   <Function Name="GetOrderDetails" Aggregate="false"     BuiltIn="false" NiladicFunction="false"     IsComposable="false"     ParameterTypeSemantics="AllowImplicitConversion"     Schema="dbo">         <Parameter Name="SalesOrderHeaderId" Type="int" Mode="in" /> </Function>     Agora a função de importação do qual você mesmo mencionou (CSDL):   <FunctionImport Name="GetOrderDetails"     EntitySet="SalesOrderDetail"     ReturnType="Collection(AdventureWorksModel.SalesOrderDetail)">   <Parameter Name="SalesOrderHeaderId" Type="Int32" Mode="in">   </Parameter> </FunctionImport>   E por ultimo o mapeamento da SP, como mencionei acima, este no MSL:   <FunctionImportMapping FunctionImportName="GetOrderDetails"            FunctionName="AdventureWorksModel.Store.GetOrderDetails"/>   E a chamada no metodo fica assim:   using (AdventureWorksEntities db = new AdventureWorksEntities())     {         int soHeaderNumber = 43659;         foreach (SalesOrderDetail order in db.GetOrderDetails(soHeaderNumber))                    Console.WriteLine("Header#: " +                    "Order#: ProductID: Quantity: Price: ",                    soHeaderNumber, order.SalesOrderDetailID, order.ProductID,                    order.OrderQty, order.UnitPrice);     }     Espero que consiga. Veja se todos estes passos estão corretos.   Aguardo seu retorno. Abraços   Att Luiz Maia  
Responder

Gostei + 0

24/09/2009

Carlos Nogueira

Oi Luiz!

Eu analisei seu post e fui checar a existência das funções e mapeamento citados no exemplo da Microsoft. No meu arquivo .edmx já contém esses itens, os quais irei colocar abaixo:

SSDL:
        <Function Name="sp_workflow_abertura_Acoes_Judiciais" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="false" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo">
          <Parameter Name="id_processo" Type="int" Mode="In" />
        </Function>

CSDL:
          <FunctionImport Name="sp_wf_abertura_acoes_judiciais">
            <Parameter Name="id_processo" Mode="In" Type="Int32" /></FunctionImport>

MSL:
<FunctionImportMapping FunctionImportName="sp_wf_abertura_acoes_judiciais" FunctionName="SMA.GENTEv1.Dados.Store.sp_workflow_abertura_Acoes_Judiciais" />

Como você já deve ter observado, diferente do exemplo da Microsoft, no meu modelo de conceito (CSDL) não foi configurado o EntitySet e o ReturnType. Esta stored procedure não vai ter nenhum retorno, e também não configurei nenhuma entidade para ela porque, o objetivo dessa stored procedure é, que ao passar o parâmetro para a mesma, pelo banco de dados a procedure irá enviar um e-mail para o usuário (procedure criada já pelo DBA para realizar essa função).

Então, no meu método na camada de negócio, após ele inserir um registro de processo, tinha o intuito de passar o id para a stored procedure mais ou menos como algo abaixo:

var execucao = (from exec in _context.sp_wf_abertura_acoes_judiciais(this._idProcesso));

Porém, na minha instância do context (variável _context) não aparece a função mapeada sp_wf_abertura_acoes_judiciais. Não sei se é esta mesmo a forma correta para executar a função no context para o que eu preciso e se eu esqueci de fazer algo a mais para que esta função possa aparecer no meu _context.

Será que existe algo a mais ou que fiz diferente para que eu possa visualizar esta função na minha camada de negócios? E conforme o exemplo que lhe passei acima da chamada para como deve ser executado a função (manda o e-mail), está correto?

Responder

Gostei + 0

24/09/2009

Luiz Maia

Ola Carlos,   Depois de analisar varias referencias sobre L2E, descobri que não há este recurso nativo, do qual é possivel executar uma SP sem retorno de valor. Pois o L2E faz um mapeamento dos objetod relacionais, e neste caso não há objeto algum. Então o mais aconselhavel é usar ADO.net mesmo para excutar esta SP.   No site da Microsoft diz que isto será melhorado em versões futuras do framework.   Mas tem um outra maneira que se fazer isto usando um recurso de "Materialização de tipos", é bem complicado, mas é o sugerido pela MSDN:     http://blogs.msdn.com/meek/archive/2008/03/26/ado-entity-framework-stored-procedure-customization.aspx   Note o uso do namespace using Microsoft.Data.Extensions;   E nos finalmente vocÊ terá algo do tipo:   var results = context     .CreateStoreCommand("GetCategories", CommandType.StoredProcedure)     .Materialize<Category>()     .Bind(categorySet); Mas para chegar ate aqui, é um longo caminho. Caso ainda queira fazer desta forma e tenha alguma dúvida, estou a disposição, ok? Abraços e aguardo retorno Att Luiz Maia  
Responder

Gostei + 0

25/09/2009

Carlos Nogueira

Oi Luiz!

Putz cara, rsrs, agora que estava animado com esse linq to entities, já li algumas melhorias que vai ter no visual studio 2010 e ai acontece isso? Quebra as pernas heim, rsrs...

Pior que estava querendo desenvolver uns softwares em casa para comercializar, e estava pensando usar ele como ferramenta ORM, e persistir como você faz, fazendo uso de stored procedures, mas ai só no linq to sql que é mais confiavel né (ou nhibernate se for o caso)? É uma pena mesmo.

Como solução eu adotei o ADO.NET mesmo, baixei o projeto de exemplo deles para extensão do linq, mas ai fazer os testes e ver se realmente funciona com o tempo que tenho aqui, é complicado.

Sei que cada projeto pode solicitar uma arquitetura diferente, mas na maioria dos que você vem trabalhando você esta usando o linq to sql mesmo, e persistindo por meio de stored procedures? Pergunto porque, como o linq to entities permite você trabalhar com mais de um banco além do sql server, por ventura em um projeto que tome a decisão de mudar de sql server para oracle, sybase, ou que tenha que ter disponibilidade para os dois ou mais, me parecia ser interessante fazer uso do linq to entities.

Mas de resto solucionou o meu problema, valeu pelo posto anterior!

Atenciosamente,

Carlos


Responder

Gostei + 0

28/09/2009

Luiz Maia

Ola Carlos,   Eu, particularmente, em meus projetos uso as Bibliotecas de Acesso da MS, Application Blocks. Faço 3 camadas, interface, negocio e acesso. E uso Stored Procedures.   Não uso linq, nHibernate ou etc. Ainda não acho que são confiáveis o bastante para uma aplicação de grande porte.   Qualquer dúvida, estamos a disposição.   Abraços   Att Luiz Maia
Responder

Gostei + 0

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.

Aceitar