2012-11-15 29 views
3

我試圖將我的MVC3項目分離成適當的DAL/Domain/ViewModel體系結構,但我遇到了AutoMapper的問題,並將計算的字段從我的域映射到我的視圖模型。AutoMapper不計算字段到標量

這裏是什麼,我試圖做一個例子:

接口

public interface IRequirement 
{ 
    int Id { get; set; } 
    ... bunch of others 
    public decimal PlanOct { get; set; } 
    public decimal PlanNov { get; set; } 
    public decimal PlanDec { get; set; } 
    ... and so on 
    decimal PlanQ1 { get; } 
    ... etc 
    decimal PlanYear { get; } 
    ... repeat for ActualOct, ActualNov ... ActualQ1 ... ActualYear... 
} 

域模型

public class Requirement : IRequirement 
{ 
    public int Id { get; set; } 
    ... bunch of others 
    public decimal PlanOct { get; set; } 
    public decimal PlanNov { get; set; } 
    public decimal PlanDec { get; set; } 
    ... and so on 
    public decimal PlanQ1 { get { return PlanOct + PlanNov + PlanDec; } } 
    ... etc 
    public decimal PlanYear { get { return PlanQ1 + PlanQ2 + PlanQ3 + PlanQ4; } } 
    ... repeat for ActualOct, ActualNov ... ActualQ1 ... ActualYear... 
} 

也有VarianceX性質,即VarianceOct這計算爲(PlanOct - ActualOct)等。

我的觀點模型看起來幾乎完全一樣,除了沒有計算領域具有默認的getter/setter語法,例如:

public decimal PlanQ1 { get; set; } 

在Global.asax中我AutoMapper的配置是這樣的:

Mapper.CreateMap<Domain.Abstract.IRequirement, Models.Requirement.Details>(); 

這工作正常除計算的所有屬性。我的計算字段(即* Q1,* Q2,* Q3,* Q4,* Year和所有方差*字段)都沒有實際映射 - 它們都以默認值0.00顯示。

我對此很尷尬,而且我也是這個和AutoMapper的新手,所以也許我錯過了一些東西。我的直覺是,由於屬性簽名不相同(即域對象只有一個非默認的getter和setter,而視圖模型具有默認的getter和setter),所以AutoMapper並沒有選擇它。但我也這樣做:

Mapper.CreateMap<Domain.Abstract.IRequirement, Models.Requirement.Details>() 
      .ForMember(dest => dest.PlanQ1, opt => opt.MapFrom(src => src.PlanQ1); 

它仍然解決爲0.我在調試器中也證實了這一點。

我在做什麼錯?

在此先感謝。

編輯1

下沃爾的意見後,我跑測試和它的工作,所以我開始在字段1 /字段2 /字段3部分一步一個時間,第一粘貼向後工作到接口/域/ view模型類並驗證它在我的控制器中工作,然後一次更改一件事。我發現,因爲我正在處理十進制類型,如果我用整數或雙精度值進行硬編碼,那麼我會得到零,但如果我轉換爲十進制或使用十進制文字,那麼它就可以工作。但只有當我手動設置它們,而不是從數據庫中提取值時。

換句話說,這是有效的(即,PlanQ1 = 6):

var D = new Requirement { PlanOct = (decimal) 1.0, PlanNov = (decimal) 2.0, PlanDec = (decimal) 3.0 }; 
var V = Mapper.Map<IRequirement, Details>(D); 

而且這個工程:

var D = new Requirement { PlanOct = 1M, PlanNov = 2M, PlanDec = 3M }; 
var V = Mapper.Map<IRequirement, Details>(D); 

但是從一個資源庫對象,這並不(拉一個單一的域對象,這反過來使用實體框架)的SQL Server拉:

var D = requirementRepository.Requirement(5); 
var V = Mapper.Map<IRequirement, Details>(D); 

以上我得到的是PlanQ1和PlanYear的0。我驗證了域對象(D)中的PlanOct = 1,PlanNov = 2和PlanDec = 3。我還驗證了所有對象(包括EF生成的對象)中的類型都是十進制的,而SQL Server類型是十進制的。我甚至嘗試映射到創建視圖模型,只是爲了排除這種可能性,我仍然PlanQ1和PlanYear得到0:

var D = requirementRepository.Requirement(5); 
var V = new Details(); 
Mapper.Map<IRequirement, Details>(D, V); 

回答

1

剛剛意識到這是沒有答案,所以我想關閉它。從技術上講,這是沒有答案的,因爲我無法讓Automapper在這種情況下出於某種原因玩好。我最終做的是回溯並在我的資源庫中創建一對映射方法,一個將DAL對象的單個實例映射到IRequirement對象,另一個映射集合。然後在存儲庫中,而不是調用Mapper.Map,我只需調用我自定義的映射方法,它就可以完美地工作。

我仍然不明白爲什麼這不起作用,但我遇到了一些其他類,其中Automapper只是拋出了,我必須手動映射至少一個或兩個字段,但Automapper確實照顧在這些情況下的其餘部分。

我敢肯定有一些事情我只是不明白呢。但無論如何,回落到部分或完全手動映射是我的解決方法。

2

PlanQ1IRequirement一員?你已經暗示它是由你最後的代碼片段引起的,但如果它不是,那麼你將得到完全按照你描述的行爲。

考慮的簡單求例如你在做什麼:

public interface IFoo 
{ 
    string Field1 { get; set; } 
    string Field2 { get; set; } 
    //string Field3 { get; } 
} 

public class Foo1 : IFoo 
{ 
    public string Field1 { get; set; } 
    public string Field2 { get; set; } 
    public string Field3 { get { return Field1 + Field2; } } 
} 
public class Foo2 
{ 
    public string Field1 { get; set; } 
    public string Field2 { get; set; } 
    public string Field3 { get; set; } 
} 

注意,在這種情況下我省略從接口Field3;現在,當我跑那麼下面的映射失敗

[TestMethod] 
public void Map() 
{ 
    Mapper.CreateMap<IFoo, Foo2>(); 
    var foo1 = new Foo1() { Field1 = "field1", Field2 = "field2" }; 
    var foo2 = new Foo2(); 
    Mapper.Map(foo1, foo2); 
    Assert.AreEqual("field1field2", foo2.Field3);//fails, not mapped 
} 

,如果我在Field3IFoo一切再次工作發表評論。用你的代碼檢查這個簡化的例子。

+0

好一點。不幸的是,PlanQ1和其他人都是在界面中定義的,因爲十進制PlanQ1 {get; }。它是否失敗,因爲它只定義了一個getter,而視圖模型有一個getter和setter? – Dave

+0

不是。我只是向接口添加了一個默認集合{},所以現在有一個setter和getter用於領域模型接口,領域模型類和視圖模型類。結果仍然爲0.00。 – Dave

+0

你最近評論過的內容是描述我的例子 - 你與我給出的例子有什麼不同?必須有導致錯誤行爲的差異。 – wal

2

考慮@Wal後,試試這個地圖,

Mapper.CreateMap<IFoo, Foo2>() 
    .ForMember(destination => destination.Field3, options => options.MapFrom(source => source.Field1 + source.Field2)); 

而且

[TestMethod] 
public void Map() 
{ 
    Mapper.CreateMap<IFoo, Foo2>() 
     .ForMember(destination => destination.Field3, options => options.MapFrom(source => source.Field1 + source.Field2)); 
    var foo1 = new Foo1() { Field1 = "field1", Field2 = "field2" }; 
    var foo2 = new Foo2(); 
    Mapper.Map(foo1, foo2); 
    Assert.AreEqual("field1field2", foo2.Field3); // True 
} 
+0

是的,我昨天做過了,但是這不違反各種OO封裝原則嗎?一個字段的計算只能在該字段中知道,客戶不應該關心實現,對嗎?我的意思是我可以做到這一點,如果它真的是解決問題的唯一方法,但它對我來說味道不好。除非我錯過了什麼? – Dave