2017-08-12 82 views
4

處理自定義映射DDD實體只讀域我有以下類,我試圖來滋潤到:小巧玲瓏 - 通過構造

public class Product 
{ 
    public readonly Sku Sku; 
    public string Name { get; private set; } 
    public string Description { get; private set; } 
    public bool IsArchived { get; private set; } 

    public Product(Sku sku, string name, string description, bool isArchived) 
    { 
     Sku = sku; 
     Name = name; 
     Description = description; 
     IsArchived = isArchived; 
    } 
} 

它使用從我的DDD實體實現的概念下面類領域模型(不相關的代碼去除,以保持代碼的短,設置爲只讀,使一成不變的一次構造):

public class Sku 
{ 
    public readonly VendorId VendorId; 
    public readonly string SkuValue; 

    public Sku(VendorId vendorId, string skuValue) 
    { 
     VendorId = vendorId; 
     SkuValue = skuValue; 
    } 
} 

public class VendorId 
{ 
    public readonly string VendorShortname; 

    public VendorId(string vendorShortname) 
    { 
     VendorShortname = vendorShortname; 
    } 
} 

我嘗試和運行參數化查詢,將水合物的產品對象:

using (connection) 
{ 
    connection.Open(); 
    return connection.QueryFirst<Product>(ReadQuery, new { VendorId = sku.VendorId.VendorShortname, SkuValue = sku.SkuValue }); 
} 

它拋出以下異常,因爲它不知道如何處理在構造函數中Sku類型:

System.InvalidOperationException:「無參數的默認構造函數 或一個匹配的簽名(系統。串廠商ID,System.String SkuValue,System.String名稱,System.String說明,System.UInt64形式 的isArchived)所需的Domain.Model.Products.Product 物化」

我使用自定義的SqlMapper.TypeHandler<Product>進行了調查,但Parse(object value)只能從VendorId數據庫列傳入單個解析值(如果它傳遞給一個值數組,我可以自己做映射)。

是否有辦法自定義對象的處理,這樣我可以在通過所有參數的構造函數,如下面:

using (connection) 
{ 
    var command = connection.CreateCommand(); 
    command.CommandText = "SELECT VendorShortname, SkuValue, Name, Description, IsArchived FROM Products WHERE [email protected] AND [email protected]"; 
    command.Parameters.AddWithValue("@VendorShortname", sku.VendorId.VendorShortname); 
    command.Parameters.AddWithValue("@SkuValue", sku.SkuValue); 
    connection.Open(); 

    var reader = command.ExecuteReader(); 
    if (reader.HasRows==false) 
     return null; 

    reader.Read(); 

    return new Product(
     new Sku(new VendorId(reader.GetString("VendorId")),reader.GetString("SkuValue")), 
     reader.GetString("Name"), 
     reader.GetString("Description"), 
     reader.GetBoolean("IsArchived")); 
} 

我想我可以創建一個特定的構造與Product(string VendorShortname, string SkuValue, string Name, string Description, UInt64 IsArchived),但我寧願(必須)在映射代碼中而不是在我的域模型中有這種擔心。

查看一些僞代碼,我可以做的是滾動我自己的ORM,但是會想通過Dapper進行類似的操作。

  1. 獲取對象的所有構造函數通過反射
  2. 如果在構造函數中的任何參數是一個類型,得到它的構造
  3. 對於每一個構造函數(包括參數),地圖構造函數的名字到SQL讀者柱(和型)

這將等同於用於VendorId(string vendorShortname)VendorShortnameNameDescriptionisArchived用於公共Product(Sku sku, string name, string description, bool isArchived) ...什麼是西米通過MongoDB的larly完成按我的答案貼在下面的鏈接,一個小巧精緻的手工映射相當於將真棒MongoDB Composite Key: InvalidOperationException: {document}.Identity is not supported

+0

'但我寧願(必須)在映射代碼中而不是在我的域模型中有這種擔心。「你能說說我們爲什麼你必須**有這種方式嗎? – mjwills

+0

我在其他存儲庫(MongoDB)的域模型中沒有任何持久性問題,在可能的情況下,我想使用SQL/Dapper,因爲它使事情更簡單。將更新我的帖子,需要做什麼,可以推出我自己的,但不想重新發明輪子,也不可以像Dapper的那樣編寫代碼 – g18c

回答

3

Execute a query and map it to a list of dynamic objects

public static IEnumerable<dynamic> Query (
    this IDbConnection cnn, 
    string sql, 
    object param = null, 
    SqlTransaction transaction = null, 
    bool buffered = true 
) 

你會進而構建使用的列表中選擇所需模式動態對象。

因此,使用從原崗位的例子中,參數化查詢將從改變...

using (connection) 
{ 
    var command = connection.CreateCommand(); 
    command.CommandText = "SELECT VendorShortname, SkuValue, Name, Description, IsArchived FROM Products WHERE [email protected] AND [email protected]"; 
    command.Parameters.AddWithValue("@VendorShortname", sku.VendorId.VendorShortname); 
    command.Parameters.AddWithValue("@SkuValue", sku.SkuValue); 
    connection.Open(); 

    var reader = command.ExecuteReader(); 
    if (reader.HasRows==false) 
     return null; 

    reader.Read(); 

    return new Product(
     new Sku(new VendorId(reader.GetString("VendorId")),reader.GetString("SkuValue")), 
     reader.GetString("Name"), 
     reader.GetString("Description"), 
     reader.GetBoolean("IsArchived")); 
} 

要...

var ReadQuery = "SELECT VendorShortname, SkuValue, Name, Description, IsArchived FROM Products WHERE [email protected] AND [email protected]"; 
using (connection) { 
    connection.Open(); 
    return connection.Query(ReadQuery, new { VendorShortname = sku.VendorId.VendorShortname, SkuValue = sku.SkuValue }) 
      .Select(row => new Product(
       new Sku(new VendorId(row.VendorShortname), row.SkuValue), 
       row.Name, 
       row.Description, 
       row.IsArchived) 
      ); 
} 

這是該框架的預期目的。只要確保直接使用的屬性映射到查詢返回的字段即可。

這可能看起來很密集,但考慮到目標對象的構造函數的複雜性質,這是一個可行的解決方案。

1

您還可以考慮將您的「域」模型與持久性分離並將其構建到其他位置的選項。例如:

  • 創建每個數據庫記錄類:ProductRecord
  • 創建一個工廠:ProductFactory
  • 獲取數據:var productRecords = connection.Query<ProductRecord>("select * from products").AsList();
  • 建立產品:factory.Build(productRecords)

一些優點:分離關注點,靈活性,適合較大項目

一些con s:更多的代碼,對於小項目來說是一個過度殺手

+0

謝謝,是的,我們已經完成了與POCO記錄類似的使用automapper,但可能會因雙班而變得痛苦。當然有一個有效的選項可以指出。 – g18c