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

SAP Sybase SQL Anywhere 16.0 (中文) » SQL Anywhere 服务器 - 编程 » .NET 应用程序编程 » SQL Anywhere .NET 数据提供程序

 

Entity Framework 支持

SQL Anywhere .NET 数据提供程序支持 Entity Framework 5.0,可从 Microsoft 获得独立的安装包。要使用 Entity Framework 5.0,必须使用 Microsoft 的 NuGet Package Manager 将其添加到 Visual Studio 中。

Entity Framework 的一个新功能是 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 16 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 16 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 ) );
                    }
                }
            }
        }
    }
}

应注意适用于 SQL Server 的 Microsoft .NET Framework 数据提供程序 (SqlClient) 与 SQL Anywhere .NET 数据提供程序在实现方式上存在一些细微差异。

  1. 其中包括了新类 SAConnectionFactory(用于实现 IDbConnectionFactory)。创建任何数据模型之前,将 Database.DefaultConnectionFactory 设置为 SAConnectionFactory 的实例,如下所示:

    Database.DefaultConnectionFactory = new SAConnectionFactory();
  2. Entity Framework Code First 的主要原则是按约定进行编码。Entity Framework 通过编码约定推算数据模型。Entity Framework 还可隐式执行多项操作。有时,开发人员可能不了解所有这些 Entity Framework 约定。不过,一些代码约定对 SQL Anywhere 无关紧要。SQL Server 和 SQL Anywhere 之间存在很大的差异。每个 SQL Server 实例可维护多个数据库,而每个 SQL Anywhere 数据库都是单个文件。

    • 如果用户使用无参数构造函数创建用户定义的 DbContext,SqlClient 将通过集成安全性连接到本地计算机上的 SQL Server Express。如果用户已经创建了登录映射,则 SQL Anywhere 提供程序将使用集成登录连接到缺省服务器。

    • 如果 Entity Framework 调用 DbDeleteDatabase 或 DbCreateDatabase(仅限于 SQL Server Express 版),则 SqlClient 将删除现有数据库并创建新数据库。SQL Anywhere 提供程序从不删除或创建数据库。它只创建或删除数据库对象(表、关系、约束等)。用户必须首先创建数据库。

    • IDbConnectionFactory.CreateConnection 方法会将字符串参数 "nameOrConnectionString" 视为数据库名称(SQL Server 的初始目录)或连接字符串。如果用户不为 DbContext 提供连接字符串,SqlClient 会将用户定义的 DbContext 类的命名空间用作初始目录,自动连接到本地计算机上的 SQL Express 服务器。对于 SQL Anywhere,nameOrConnectionString 参数只包含连接字符串。此时将忽略数据库名称,而使用集成登录。

  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 值都将发生相应的变化。

    SQL Anywhere 提供程序不支持 TimeStamp 数据标注属性。

  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" );
            }
        }
    }