Birden Çok Sonuç Kümesine Sahip Saklı Yordamlar

Bazen saklı yordamları kullanırken birden fazla sonuç kümesi döndürmeniz gerekir. Bu senaryo genellikle tek bir ekran oluşturmak için gereken veritabanı gidiş dönüş sayısını azaltmak için kullanılır. EF5'ten önce, Entity Framework saklı yordamın çağrılmasına izin verirdi, ancak yalnızca ilk sonuç kümesini çağıran koda döndürürdü.

Bu makalede, Entity Framework'teki bir saklı yordamdan birden fazla sonuç kümesine erişmek için kullanabileceğiniz iki yol gösterilir. Yalnızca kod kullanan ve hem Kod Öncelikli hem de EF Tasarımcısı ile çalışan bir yapı ile yalnızca EF Tasarımcısı ile çalışan bir yapı. Bunun için araç ve API desteği, Entity Framework'ün gelecek sürümlerinde geliştirilmelidir.

Model

Bu makaledeki örneklerde, bir blogda birçok gönderinin bulunduğu ve bir gönderinin tek bir bloga ait olduğu temel bir Blog ve Gönderiler modeli kullanılır. Veritabanında aşağıdaki gibi tüm blogları ve gönderileri döndüren bir saklı yordam kullanacağız:

    CREATE PROCEDURE [dbo].[GetAllBlogsAndPosts]
    AS
        SELECT * FROM dbo.Blogs
        SELECT * FROM dbo.Posts

Kodla Birden Çok Sonuç Kümesine Erişme

Saklı yordamımızı yürütmek üzere ham bir SQL komutu vermek için use kodunu yürütebiliriz. Bu yaklaşımın avantajı, hem Code First hem de EF Designer ile çalışmasıdır.

Birden çok sonuç kümesinin çalışmasını sağlamak için IObjectContextAdapter arabirimini kullanarak ObjectContext API'sine düşmemiz gerekiyor.

Bir ObjectContext elde ettikten sonra, saklı yordamımızın sonuçlarını normal bir şekilde EF'te izlenip kullanılabilecek varlıklara çevirmek için Translate metodunu kullanabiliriz. Aşağıdaki kod örneği bunu uygulamada gösterir.

    using (var db = new BloggingContext())
    {
        // If using Code First we need to make sure the model is built before we open the connection
        // This isn't required for models created with the EF Designer
        db.Database.Initialize(force: false);

        // Create a SQL command to execute the sproc
        var cmd = db.Database.Connection.CreateCommand();
        cmd.CommandText = "[dbo].[GetAllBlogsAndPosts]";

        try
        {

            db.Database.Connection.Open();
            // Run the sproc
            var reader = cmd.ExecuteReader();

            // Read Blogs from the first result set
            var blogs = ((IObjectContextAdapter)db)
                .ObjectContext
                .Translate<Blog>(reader, "Blogs", MergeOption.AppendOnly);   


            foreach (var item in blogs)
            {
                Console.WriteLine(item.Name);
            }        

            // Move to second result set and read Posts
            reader.NextResult();
            var posts = ((IObjectContextAdapter)db)
                .ObjectContext
                .Translate<Post>(reader, "Posts", MergeOption.AppendOnly);


            foreach (var item in posts)
            {
                Console.WriteLine(item.Title);
            }
        }
        finally
        {
            db.Database.Connection.Close();
        }
    }

Translate yöntemi, yordamı yürütürken aldığımız okuyucuyu, bir EntitySet adını ve bir MergeOption'ı kabul eder. EntitySet adı, türetilmiş bağlamınızdaki DbSet özelliğiyle aynı olacaktır. MergeOption enum'u, aynı varlık bellekte zaten varsa sonuçların nasıl işleneceğini denetler.

Burada NextResult'u çağırmadan önce blog koleksiyonunu yineleyeceğiz; yukarıdaki kod nedeniyle bu önemlidir çünkü ilk sonuç kümesinin sonraki sonuç kümesine geçmeden önce tüketilmesi gerekir.

İki çeviri yöntemi çağrıldıktan sonra Blog ve Post varlıkları EF tarafından diğer varlıklarla aynı şekilde izlenir ve böylece değiştirilebilir veya silinebilir ve normal şekilde kaydedilebilir.

Uyarı

EF, Translate yöntemini kullanarak varlıklar oluştururken hiçbir eşlemeyi hesaba katmıyor. Sonuç kümesindeki sütun adlarını sınıflarınızdaki özellik adlarıyla eşleştirmeniz yeterlidir.

Uyarı

Gecikmeli yükleme etkinse, blog varlıklarından birinde post özelliğine erişiyorsanız, zaten hepsini yüklemiş olsak bile EF tüm gönderileri gevşek bir şekilde yüklemek için veritabanına bağlanır. Bunun nedeni, EF'in tüm gönderileri yükleyip yüklemediğiniz veya veritabanında daha fazlası olup olmadığını bilmemesidir. Bundan kaçınmak istiyorsanız gecikmeli yüklemeyi devre dışı bırakmanız gerekir.

EDMX'te Yapılandırılmış Birden Çok Sonuç Kümesi

Uyarı

EDMX'te birden çok sonuç kümesi yapılandırabilmek için .NET Framework 4.5'i hedeflemeniz gerekir. .NET 4.0'i hedef alıyorsanız, önceki bölümde gösterilen kod tabanlı yöntemi kullanabilirsiniz.

EF Designer'ı kullanıyorsanız, modelinizi değiştirerek döndürülecek farklı sonuç kümelerini de anlayabilirsiniz. Önceden bilinmesi gereken bir şey, aracın birden çok sonuç kümesini desteklememesidir, bu nedenle edmx dosyasını manuel olarak düzenlemeniz gerekir. edmx dosyasını bu şekilde düzenlemek işe yarayacaktır, ancak vs'de modelin doğrulanması da bozulacaktır. Bu nedenle modelinizi doğrularsanız her zaman hata alırsınız.

  • Bunu yapmak için tek bir sonuç kümesi sorgusunda olduğu gibi saklı yordamı modelinize eklemeniz gerekir.

  • Bunu yaptıktan sonra modelinize sağ tıklamanız ve Birlikte Aç.. ve ardından Xml'i seçmeniz gerekir

    Olarak Aç

Modeli XML olarak açtıktan sonra aşağıdaki adımları uygulamanız gerekir:

  • Modelinizde karmaşık tür ve işlev içeri aktarmayı bulun:
    <!-- CSDL content -->
    <edmx:ConceptualModels>

    ...

      <FunctionImport Name="GetAllBlogsAndPosts" ReturnType="Collection(BlogModel.GetAllBlogsAndPosts_Result)" />

    ...

      <ComplexType Name="GetAllBlogsAndPosts_Result">
        <Property Type="Int32" Name="BlogId" Nullable="false" />
        <Property Type="String" Name="Name" Nullable="false" MaxLength="255" />
        <Property Type="String" Name="Description" Nullable="true" />
      </ComplexType>

    ...

    </edmx:ConceptualModels>

 

  • Karmaşık türü kaldır
  • İşlev içeri aktarmayı varlıklarınızla eşlenecek şekilde güncelleştirin; bizim durumumuzda aşağıdaki gibi görünür:
    <FunctionImport Name="GetAllBlogsAndPosts">
      <ReturnType EntitySet="Blogs" Type="Collection(BlogModel.Blog)" />
      <ReturnType EntitySet="Posts" Type="Collection(BlogModel.Post)" />
    </FunctionImport>

Bu, modele saklı yordamın blog girdilerinden ve gönderi girdilerinden oluşan iki koleksiyon döndüreceğini bildirir.

  • İşlev eşleme öğesini bulun:
    <!-- C-S mapping content -->
    <edmx:Mappings>

    ...

      <FunctionImportMapping FunctionImportName="GetAllBlogsAndPosts" FunctionName="BlogModel.Store.GetAllBlogsAndPosts">
        <ResultMapping>
          <ComplexTypeMapping TypeName="BlogModel.GetAllBlogsAndPosts_Result">
            <ScalarProperty Name="BlogId" ColumnName="BlogId" />
            <ScalarProperty Name="Name" ColumnName="Name" />
            <ScalarProperty Name="Description" ColumnName="Description" />
          </ComplexTypeMapping>
        </ResultMapping>
      </FunctionImportMapping>

    ...

    </edmx:Mappings>
  • Sonuç eşlemesini döndürülen her varlık için aşağıdaki gibi bir değerle değiştirin:
    <ResultMapping>
      <EntityTypeMapping TypeName ="BlogModel.Blog">
        <ScalarProperty Name="BlogId" ColumnName="BlogId" />
        <ScalarProperty Name="Name" ColumnName="Name" />
        <ScalarProperty Name="Description" ColumnName="Description" />
      </EntityTypeMapping>
    </ResultMapping>
    <ResultMapping>
      <EntityTypeMapping TypeName="BlogModel.Post">
        <ScalarProperty Name="BlogId" ColumnName="BlogId" />
        <ScalarProperty Name="PostId" ColumnName="PostId"/>
        <ScalarProperty Name="Title" ColumnName="Title" />
        <ScalarProperty Name="Text" ColumnName="Text" />
      </EntityTypeMapping>
    </ResultMapping>

Sonuç kümelerini varsayılan olarak oluşturulan gibi karmaşık türlere eşlemek de mümkündür. Bunu yapmak için, bunları kaldırmak yerine yeni bir karmaşık tür oluşturursunuz ve yukarıdaki örneklerde varlık adlarını kullandığınız her yerde karmaşık türleri kullanırsınız.

Bu eşlemeler değiştirildikten sonra modeli kaydedebilir ve saklı yordamı kullanmak için aşağıdaki kodu yürütebilirsiniz:

    using (var db = new BlogEntities())
    {
        var results = db.GetAllBlogsAndPosts();

        foreach (var result in results)
        {
            Console.WriteLine("Blog: " + result.Name);
        }

        var posts = results.GetNextResult<Post>();

        foreach (var result in posts)
        {
            Console.WriteLine("Post: " + result.Title);
        }

        Console.ReadLine();
    }

Uyarı

Modeliniz için edmx dosyasını el ile düzenlerseniz, modeli veritabanından yeniden oluşturursanız üzerine yazılır.

Özet

Burada Entity Framework kullanarak birden çok sonuç kümesine erişmenin iki farklı yöntemini gösterdik. Her ikisi de durumunuz ve tercihlerinize bağlı olarak eşit olarak geçerlidir ve koşullarınız için en uygun olanı seçmeniz gerekir. Entity Framework'ün gelecek sürümlerinde birden çok sonuç kümesi desteğinin geliştirilmesi planlanmaktadır ve bu belgedeki adımların gerçekleştirilmesi artık gerekli olmayacaktır.