2017-09-01 74 views
0

我新的AutoMapper。我想將DbGeography類型的屬性(如PlayerFromCache.Position)映射到PlayerFromDb.Position,這兩種類型的玩家。我不斷收到一個錯誤,所以我崩潰了的代碼最簡單的版本:Automapper與DbGeography結果異常:「在WellKnownValue ......」

Mapper.Initialize(cfg => 
{ 
    cfg.CreateMap<DbGeography, DbGeography>(); 
}); 

var pos1 = DbGeography.PointFromText($"POINT(11.0 12.0)", DbGeography.DefaultCoordinateSystemId); 
var pos2 = DbGeography.PointFromText($"POINT(22.0 23.0)", DbGeography.DefaultCoordinateSystemId); 

Mapper.Map(pos1, pos2); 

這將導致異常:

的WellKnownValue財產的目的是支持序列化和反序列化和不應該直接設置。

我被卡住了。任何幫助,將不勝感激。

當我忽略WellKnownValue,則映射不起作用:

Mapper.Initialize(cfg => 
{ 
    cfg.CreateMap<DbGeography, DbGeography>() 
     .ForMember(x => x.WellKnownValue, opt => opt.Ignore()); ; 
}); 

映射POS2仍然是22/23

回答

2

鑑於DbGeography是不可變的類型,沒有必要創建它的副本。你縮減的代碼映射到DbGeography的現有實例將不起作用,但這不應該起作用,反正也不是你的最終目標,所以你可以忘記這一點。

卸下cfg.CreateMap<DbGeography, DbGeography>();應引起DbGeography類型的屬性進行直接分配,而無需克隆。

+0

請在Lucian的回答下看到我的評論。 – Tillito

+0

@Tillito我在一個最小化的獨立程序中驗證了AutoMapper的行爲與我描述的方式相同,而且我無法知道您發佈的評論+答案與您提問的問題相關。你確定你最終沒有發佈一個與你在此問的問題不同的問題嗎? – hvd

+0

是的,你是對的:事實證明,問題並不那麼簡單。它也包含實體框架。你認爲我應該刪除這個問題嗎?另一方面,我的答案可以幫助其他人嘗試使用dbgeography字段緩存對象,並像我一樣使用EF和Automapper ... – Tillito

0

AM之後通過設置屬性工程和DbGeography沒有性質可以設置。所以除非你想用其他原因使用AM,否則自己做映射似乎更容易。

+0

我試過了。映射不再適用。我將這添加到了我的問題中。 – Tillito

+0

已更新。沒有什麼可以設置的。 –

+0

問題在於,該位置總是被標記爲實體框架的變化的屬性,導致性能大幅下降,因爲在現實世界中,位置很少變化。我想,最後我簡化了我的示例代碼。 – Tillito

0

所以,事實證明,我已經簡化我的問題太多了:我在下面的評論,我想保存玩家數據庫中的屬性的映射後,但只有在情況在發生改變。不幸的是,在Automapper上沒有任何配置,實體框架總是會假設位置已經改變,這導致了對數據庫的許多不通常的更新。

最後,我解決了自己的問題。我希望這可以幫助其他人。

我的簡化代碼:

/// <summary> 
/// Players held in cached and stored in database using Entity Framework 
/// </summary> 
public class SimplePlayer 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public DbGeography Position { get; set; } 

    [NotMapped] 
    public string SerializedPosition 
    { 
     get { return Position.WellKnownValue.WellKnownText; } 
     set 
     { 
      //-- This is crucial for the redundant updates in EF: 
      if (value != Position.WellKnownValue.WellKnownText) 
      { 
       Position = DbGeography.FromText(value); 
      } 
     } 
    } 
} 

/// <summary> 
/// Get a player from the cache and only save 
/// it to the database if any property has changed 
/// </summary> 
/// <param name="context"></param> 
/// <returns></returns> 
public int UpdatePlayer(DbContext context) 
{ 
    Mapper.Initialize(cfg => 
    { 
     cfg.CreateMap<SimplePlayer, SimplePlayer>().ForMember(m => m.Position, opt => opt.Ignore()); 
    }); 

    //-- Get the player from the cache 
    var player = Game.Players.First(); 

    //-- When you un-comment this line, the result will be 1 
    //-- and the position will be changed in the database 
    // player.Position = GeographyHelper.CreatePoint(11, 11); 

    //-- Get the same player from the database 
    var playerFromDb = context.Set<Player>().Find(player.ID); 

    //-- Map the properties 
    Mapper.Map(player, playerFromDb); 

    //-- Save changes to the database if there are any 
    int countChanges = context.SaveChanges(); 

    return countChanges; 
} 

所以,對我來說這是至關重要的UpdatePlayer只會導致1如果任何屬性發生了變化。

對不起,我把這個問題太簡單了,感謝你的幫助。