1. 程式人生 > >輕量ORM-SqlRepoEx (十五)最佳實踐之資料對映(Map)

輕量ORM-SqlRepoEx (十五)最佳實踐之資料對映(Map)

簡介:SqlRepoEx是 .Net平臺下相容.NET Standard 2.0人一個輕型的ORM。解決了Lambda轉Sql語句這一難題,SqlRepoEx使用的是Lambda表示式,所以,對c#程式設計師來說,是非常簡單的,其語法特點與Linq to Sql極為相似。不僅實現了完整的Select、Insert、Update、Delete等語句解析器,同時,也實現了Select、where、order by等子句,這些語句與子句均支援匯出SQL語句,使得拼接複雜場景SQL語句變得輕鬆,SqlRepoEx很快其原生資料訪問與Dapper不相上下,SqlRepoEx本身支援Sql Server與MySql方言,同時通過SqlRepoEx.Normal支援非方言SQL。SqlRepoEx沒侵入性,僅通過簡單的幾個特性,就能讓類與資料庫關聯起來;

 

*本系列以靜態工廠為例;

*資料來源於Northwind資料庫;

*完整的程式碼見 https://github.com/AzThinker/SqlRepoEx2.0StartGuid  https://gitee.com/azthinker/SqlRepoEx2.0StartGuid

 

1、從 SqlRepoEx 2.2.1 起,標識資料據欄位的特性標識改為使用System.ComponentModel.DataAnnotations中的宣告,降低使用難度,當然 SqlRepoEx 中自定義的特性依然是支援的。

2、只有以類屬性定義的,才能作為資料欄位使用, SqlRepoEx 只反身屬性。

3、SqlRepoEx 不使用XML檔案來對映關係

 

一、表名

1、如果不使用任何特性, SqlRepoEx會將當前類名當成數名。

如:

 public sealed class AzProducts

    {

    ...

    }

    會返回形如  select ...  from AzProducts

    顯然,AzCategories在資料庫中不存在,當然,如果類名與資料庫中對應的表名一至,是可以不用標識的。

 

  2、使用 Table 特性,定義在System.ComponentModel.DataAnnotations中

[Table("Products")]

 public sealed class AzProducts

    {

    ...

    }

 會返回形如  select ...  from Products

 

 3、使用 TableName特性,定義在SqlRepoEx.Core.CustomAttribute中

[TableName("Products")]

 public sealed class AzProducts

    {

...

    }

 同樣會返回形如  select ...  from Products

 當然,使用哪種,按各自的喜好

 

 二、關鍵欄位

 1、如果未使用任何特性,在使用,For() 方法時,不會自動的產生Where條件語句。

    [Table("Products")]

    public sealed class AzProducts

    {

public int ProductID { get; set; }

...

    }

 當使用

 AzProducts azProducts = new AzProducts { ProductName2 = "testvalue", ProductID = 82 };

var resultUpdate = repository.Delete().For(azProducts);

只會產生

DELETE [dbo].[Products]

當然,這不所期望的

 

  2、使用 Key 特性 Table 定義在System.ComponentModel.DataAnnotations中

[Table("Products")]

 public sealed class AzProducts

    {

[Key]

public int ProductID { get; set; }

...

    }

 會返回形如 DELETE [dbo].[Products] WHERE  [ProductID] = 82;

 

 3、使用 KeyField 特性 Table定義在SqlRepoEx.Core.CustomAttribute中

[TableName("Products")]

 public sealed class AzProducts

    {

 [KeyField]

 public int ProductID { get; set; }

...

    }

 同樣會返回形如 DELETE [dbo].[Products] WHERE  [ProductID] = 82;

 

三、標識欄位(自增欄位)

 1、如果未使用任何特性,在使用,For() 方法時,在增加操作時,不會返回自增自段的實際值。

    [Table("Products")]

    public sealed class AzProducts

    {

public int ProductID { get; set; }

...

    }

 當使用

AzProducts azProducts = new AzProducts { ProductName2 = "testvalue" };

            var resultinsert = repository

                                    .Insert()

                                    .For(azProducts);

只會產生

INSERT [dbo].[Products]([ProductName],[SupplierID],[CategoryID],[QuantityPerUnit],[UnitPrice],[UnitsInStock],[UnitsOnOrder],[ReorderLevel],[Discontinued])

VALUES('testvalue',NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);

 

  2、使用 DatabaseGenerated 特性,定義在System.ComponentModel.DataAnnotations中

[Table("Products")]

 public sealed class AzProducts

    {

[Key]

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]

public int ProductID { get; set; }

...

    }

 會返回形如

INSERT [dbo].[Products]([ProductName],[SupplierID],[CategoryID],[QuantityPerUnit],[UnitPrice],[UnitsInStock],[UnitsOnOrder],[ReorderLevel],[Discontinued])

VALUES('testvalue',NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);

SELECT [ProductID],[ProductName] as ProductName2,[SupplierID],[CategoryID],[QuantityPerUnit],[UnitPrice],[UnitsInStock],[UnitsOnOrder],[ReorderLevel],[Discontinued]

FROM [dbo].[Products]

WHERE [ProductID] = SCOPE_IDENTITY();

 

 3、使用 IdentityField 特性,定義在SqlRepoEx.Core.CustomAttribute中

[TableName("Products")]

 public sealed class AzProducts

    {

[KeyField]

[IdentityField]

public int ProductID { get; set; }

 ...

    }

 同樣會返回形如

INSERT [dbo].[Products]([ProductName],[SupplierID],[CategoryID],[QuantityPerUnit],[UnitPrice],[UnitsInStock],[UnitsOnOrder],[ReorderLevel],[Discontinued])

VALUES('testvalue',NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);

SELECT [ProductID],[ProductName] as ProductName2,[SupplierID],[CategoryID],[QuantityPerUnit],[UnitPrice],[UnitsInStock],[UnitsOnOrder],[ReorderLevel],[Discontinued]

FROM [dbo].[Products]

WHERE [ProductID] = SCOPE_IDENTITY();

 

四、非欄位屬性

1、如果未使用任何特性,如下面屬性 public string Supplier { get; set; }。此屬性在資料庫中無對應的欄位

    [Table("Products")]

    public sealed class AzProducts

    {

[Key]

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]

public int ProductID { get; set; }

public string Supplier { get; set; }

...

    }

 當使用

var result = repository.Query();

會產生形如

select ProductID,Supplier ....

 

  2、使用 NotMapped 特性,定義在System.ComponentModel.DataAnnotations中

[Table("Products")]

 public sealed class AzProducts

    {

[Key]

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]

public int ProductID { get; set; }

[NotMapped]

public string Supplier { get; set; }

 ...

    }

 當使用

var result = repository.Query();

時,Supplier 不會出現在查詢語句中,但要注意,當使用選擇器來查詢時,何然會出現在Select語句中;

如 var result = repository.Query().Select(c=>c.ProductID,c=>c.Supplier);

 

 3、使用 NonDatabaseField 特性,定義在SqlRepoEx.Core.CustomAttribute中

[TableName("Products")]

 public sealed class AzProducts

    {

[Key]

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]

public int ProductID { get; set; }

[NonDatabaseField]

public string Supplier { get; set; }

 ...

    }

 當使用

var result = repository.Query();

時,Supplier 不會出現在查詢語句中,但要注意,當使用選擇器來查詢時,何然會出現在Select語句中;

如 var result = repository.Query().Select(c=>c.ProductID,c=>c.Supplier);

 

五、指定屬性對應的資料庫欄位名

有時,類屬性名與資料庫中的欄位名不完全是一一對應的,所以需要指定實際欄位名

使用 Column 特性,定義在System.ComponentModel.DataAnnotations中,SqlRepoEx中沒有對應的特性。

如下列類中的  ProductName2 屬性,對應的資料庫欄位實為 ProductName

[TableName("Products")]

 public sealed class AzProducts

    {

[Key]

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]

public int ProductID { get; set; }

[NonDatabaseField]

public string Supplier { get; set; }

[Column("ProductName")]

 public string ProductName2 { get; set; }

         ...

    }