Click here to view and discuss this page in DocCommentXchange. In the future, you will be sent there automatically.

SQL Anywhere 12.0.1 » SQL Anywhere サーバー プログラミング » .NET アプリケーションプログラミング » SQL Anywhere .NET データプロバイダー

 

Entity Framework のサポート

SQL Anywhere .NET データプロバイダーでは Entity Framework 4.2 がサポートされています。Entity Framework は Microsoft から別個のパッケージとして入手できます。Entity Framework 4.2 を使用するには、Microsoft の NuGet Package Manager を使用して Visual Studio に追加する必要があります。

Entity Framework の新機能の 1 つに Code First があります。この機能では異なる開発ワークフローが可能です。C# または VB.NET のクラスを記述するだけでデータモデルが定義され、データベースオブジェクトにマッピングされます。デザイナを開く必要も XML マッピングファイルを定義する必要もありません。または、データの注釈や Fluent API を使用して追加の設定を実行することもできます。モデルを使用して、データベーススキーマを生成したり既存のデータベースにマッピングしたりできます。

次の例は、このモデルを使用して新しいデータベースオブジェクトを作成します。



using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using iAnywhere.Data.SQLAnywhere;

namespace CodeFirstExample
{
    [Table( "EdmCategories", Schema = "DBA" )]
    public class Category
    {
        public string CategoryID { get; set; }
        [MaxLength( 64 )]
        public string Name { get; set; }

        public virtual ICollection<Product> Products { get; set; }
    }

    [Table( "EdmProducts", Schema = "DBA" )]
    public class Product
    {
        public int ProductId { get; set; }
        [MaxLength( 64 )]
        public string Name { get; set; }
        public string CategoryID { get; set; }

        public virtual Category Category { get; set; }
    }

    [Table( "EdmSuppliers", Schema = "DBA" )]
    public class Supplier
    {
        [Key]
        public string SupplierCode { get; set; }
        [MaxLength( 64 )]
        public string Name { get; set; }
    }

    public class Context : DbContext
    {
        public Context() : base() { }
        public Context( string connStr ) : base( connStr ) { }

        public DbSet<Category> Categories { get; set; }
        public DbSet<Product> Products { get; set; }
        public DbSet<Supplier> Suppliers { get; set; }

        protected override void OnModelCreating( DbModelBuilder modelBuilder )
        {
            modelBuilder.Entity<Supplier>().Property( s => s.Name ).IsRequired();
        }
    }
 
    class Program
    {
        static void Main( string[] args )
        {
            Database.DefaultConnectionFactory = new SAConnectionFactory();
            Database.SetInitializer<Context>( new DropCreateDatabaseAlways<Context>() );

            using ( var db = new Context( "DSN=SQL Anywhere 12 Demo" ) )
            {
                var query = db.Products.ToList();
            }
        }
    }
}

この例を構築して実行するには、次のアセンブリ参照を追加する必要があります。

EntityFramework
iAnywhere.Data.SQLAnywhere.v4.0
System.ComponentModel.DataAnnotations
System.Data.Entity

次の例は、既存のデータベースにマッピングします。



using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using iAnywhere.Data.SQLAnywhere;

namespace CodeFirstExample
{
    [Table( "Customers", Schema = "GROUPO" )]
    public class Customer
    {
        [Key()]
        public int ID { get; set; }
        public string SurName { get; set; }
        public string GivenName { get; set; }
        public string Street { get; set; }
        public string City { get; set; }
        public string State { get; set; }
        public string Country { get; set; }
        public string PostalCode { get; set; }
        public string Phone { get; set; }
        public string CompanyName { get; set; }

        public virtual ICollection<Contact> Contacts { get; set; }
    }

    [Table( "Contacts", Schema = "GROUPO" )]
    public class Contact
    {
        [Key()]
        public int ID { get; set; }
        public string SurName { get; set; }
        public string GivenName { get; set; }
        public string Title { get; set; }
        public string Street { get; set; }
        public string City { get; set; }
        public string State { get; set; }
        public string Country { get; set; }
        public string PostalCode { get; set; }
        public string Phone { get; set; }
        public string Fax { get; set; }

        [ForeignKey( "Customer" )]
        public int CustomerID { get; set; }
        public virtual Customer Customer { get; set; }
    }

    public class Context : DbContext
    {
        public Context() : base() { }
        public Context( string connStr ) : base( connStr ) { }

        public DbSet<Contact> Contacts { get; set; }
        public DbSet<Customer> Customers { get; set; }
    }

    class Program
    {
        static void Main( string[] args )
        {
            Database.DefaultConnectionFactory = new SAConnectionFactory();
            Database.SetInitializer<Context>( null );

            using ( var db = new Context( "DSN=SQL Anywhere 12 Demo" ) )
            {
                foreach ( var customer in db.Customers.ToList() )
                {
                    Console.WriteLine( "Customer - " + string.Format( 
                        "{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}",
                        customer.ID, customer.SurName, customer.GivenName, 
                        customer.Street, customer.City, customer.State, 
                        customer.Country, customer.PostalCode, 
                        customer.Phone, customer.CompanyName ) );

                    foreach ( var contact in customer.Contacts )
                    {
                        Console.WriteLine( "    Contact - " + string.Format( 
                            "{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}",
                            contact.ID, contact.SurName, contact.GivenName, 
                            contact.Title, 
                            contact.Street, contact.City, contact.State, 
                            contact.Country, contact.PostalCode, 
                            contact.Phone, contact.Fax ) );
                    }
                }
            }
        }
    }
}

Microsoft SQL Server SqlClient プロバイダーと SQL Anywhere .NET プロバイダーとでは、実装の詳細部分でいくつかの違いがあり、それらを理解しておく必要があります。

  1. 新しいクラス SAConnectionFactory (IDbConnectionFactory を実装) が追加されています。次のように、Database.DefaultConnectionFactory に SAConnectionFactory のインスタンスを設定してから、データモデルを作成します。

    Database.DefaultConnectionFactory = new SAConnectionFactory();
  2. Entity Framework の Code First では、原則として規則によるコーディングを行います。Entity Framework では、規則をコーディングすることによってデータモデルが推測されます。また、自動的な処理が多数行われます。場合によっては、開発者が Entity Framework のすべての規則を把握できないこともあります。しかし、SQL Anywhere で意味を持たないコード規則もあります。SQL Server と SQL Anywhere の間には大きな違いがあります。SQL Server のインスタンスはすべて複数のデータベースを保持しますが、SQL Anywhere のデータベースはすべて単一のファイルです。

    • ユーザーがパラメーターのないコンストラクターを使用してユーザー定義の DbContext を作成した場合、SqlClient では統合セキュリティを使用してローカルマシンの SQL Server Express に接続します。SQL Anywhere プロバイダーでは、ユーザーがすでにログインマッピングを作成している場合、統合ログインを使用してデフォルトのサーバーに接続します。

    • SqlClient では、EF から DbDeleteDatabase または DbCreateDatabase を呼び出したときに、既存のデータベースを削除して新しいデータベースを作成します (SQL Server Express Edition のみ)。SQL Anywhere プロバイダーではデータベースの削除や作成をすることは決してなく、データベースオブジェクト (テーブル、関係、制約など) を作成または削除します。ユーザーは最初にデータベースを作成する必要があります。

    • IDbConnectionFactory.CreateConnection メソッドでは、文字列パラメーター "nameOrConnectionString" がデータベース名 (SQL Server では初期カタログ) または接続文字列として扱われます。ユーザーが DbContext の接続文字列を指定しない場合、SqlClient では、ユーザー定義の DbContext クラスのネームスペースを初期カタログとして使用し、ローカルマシンの SQL Express サーバーに自動的に接続します。SQL Anywhere では、このパラメーターに接続文字列のみ含めることができます。データベース名は無視され、代わりに統合ログインが使用されます。

  3. SQL Server SqlClient API では、データ注釈属性 TimeStamp を持つカラムが、SQL Server のデータ型 timestamp/rowversion にマッピングされます。SQL Server の timestamp/rowversion については開発者のあいだで誤解されている面があります。SQL Server の timestamp/rowversion データ型は、SQL Anywhere や他のほとんどのデータベースベンダーとは異なります。

    • SQL Server の timestamp/rowversion はバイナリ (8) です。日付と時刻の組み合わせ値はサポートされていません。SQL Anywhere でサポートされている timestamp というデータ型は、SQL Server の datetime データ型と同等です。

    • SQL Server の timestamp/rowversion 値はユニークであることが保証されています。SQL Anywhere の timestamp 値はユニークではありません。

    • SQL Server の timestamp/rowversion 値は、ローが更新されるたびに変更されます。

    TimeStamp データ注釈属性は SQL Anywhere プロバイダーではサポートされていません。

  4. Entity Framework 4.1 のデフォルトでは、スキーマ名または所有者名が常に dbo に設定されます。これは SQL Server のデフォルトのスキーマです。ただし、dbo は SQL Anywhere では適切ではありません。SQL Anywhere では、データ注釈か Fluent API のどちらかを使用して、テーブル名を持つスキーマ名 (GROUPO など) を指定する必要があります。次に例を示します。



    namespace CodeFirstTest
    {
        public class Customer
        {
            [Key()]
            public int ID { get; set; }
            public string SurName { get; set; }
            public string GivenName { get; set; }
            public string Street { get; set; }
            public string City { get; set; }
            public string State { get; set; }
            public string Country { get; set; }
            public string PostalCode { get; set; }
            public string Phone { get; set; }
            public string CompanyName { get; set; }
    
            public virtual ICollection<Contact> Contacts { get; set; }
        }
    
        public class Contact
        {
            [Key()]
            public int ID { get; set; }
            public string SurName { get; set; }
            public string GivenName { get; set; }
            public string Title { get; set; }
            public string Street { get; set; }
            public string City { get; set; }
            public string State { get; set; }
            public string Country { get; set; }
            public string PostalCode { get; set; }
            public string Phone { get; set; }
            public string Fax { get; set; }
    
            [ForeignKey( "Customer" )]
            public int CustomerID { get; set; }
            public virtual Customer Customer { get; set; }
        }
    
        [Table( "Departments", Schema = "GROUPO" )]
        public class Department
        {
            [Key()]
            public int DepartmentID { get; set; }
            public string DepartmentName { get; set; }
            public int DepartmentHeadID { get; set; }
        }
    
        public class Context : DbContext
        {
            public Context() : base() { }
            public Context( string connStr ) : base( connStr ) { }
    
            public DbSet<Contact> Contacts { get; set; }
            public DbSet<Customer> Customers { get; set; }
            public DbSet<Department> Departments { get; set; }
    
            protected override void OnModelCreating( DbModelBuilder modelBuilder )
            {
                modelBuilder.Entity<Contact>().ToTable( "Contacts", "GROUPO" );
                modelBuilder.Entity<Customer>().ToTable( "Customers", "GROUPO" );
            }
        }
    }