Asp.net mvc 3 AutoMapper没有';将计算字段映射到标量

Asp.net mvc 3 AutoMapper没有';将计算字段映射到标量,asp.net-mvc-3,automapper,Asp.net Mvc 3,Automapper,我试图将我的MVC3项目分离到一个合适的DAL/Domain/ViewModel体系结构中,但是我遇到了AutoMapper和将计算字段从我的域映射到我的视图模型的问题 下面是我尝试做的一个例子: 接口 public interface IRequirement { int Id { get; set; } ... bunch of others public decimal PlanOct { get; set; } public decimal PlanNov

我试图将我的MVC3项目分离到一个合适的DAL/Domain/ViewModel体系结构中,但是我遇到了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属性,即计算为(PlanOct-ActualOct)的VarianceAct等

我的视图模型看起来几乎完全相同,只是它没有使用计算字段,而是使用默认的getter/setter语法,例如:

public decimal PlanQ1 { get; set; }
Global.asax中的自动映射配置如下所示:

Mapper.CreateMap<Domain.Abstract.IRequirement, Models.Requirement.Details>();
Mapper.CreateMap();
这适用于除计算属性外的所有属性。我的计算字段(即*Q1、*Q2、*Q3、*Q4、*Year和所有方差*字段)都没有实际映射——它们都以默认值0.00显示

我对此感到很困惑,而且我也是这方面的新手和汽车制造商,所以我可能错过了一些东西。我的直觉是,由于属性签名不完全相同(即域对象只有一个非默认的getter和setter,而视图模型有默认的getter和setter),所以AutoMapper没有选择它。但我也做到了:

Mapper.CreateMap<Domain.Abstract.IRequirement, Models.Requirement.Details>()
            .ForMember(dest => dest.PlanQ1, opt => opt.MapFrom(src => src.PlanQ1);
Mapper.CreateMap()
.ForMember(dest=>dest.PlanQ1,opt=>opt.MapFrom(src=>src.PlanQ1);
它仍然解析为0。我也在调试器中确认了这一点

我做错了什么

提前谢谢

编辑1

在遵循Wal的建议后,我运行了测试,它成功了,所以我开始一步一步地向后工作,首先将Field1/Field2/Field3部分粘贴到interface/domain/view模型类中,并验证它在我的控制器中是否有效,然后一次更改一件事。我发现,由于我处理的是十进制类型,如果我用整数值或双数值表示的rd代码则为零,但如果我转换为十进制或使用十进制文字,则它可以工作。但只有在我手动设置它们时,而不是从数据库中提取值时,它才能工作

换句话说,这是可行的(即PlanQ1=6):

vard=新需求{PlanOct=(十进制)1.0,planov=(十进制)2.0,PlanDec=(十进制)3.0};
var V=映射器映射(D);
这是有效的:

var D = new Requirement { PlanOct = 1M, PlanNov = 2M, PlanDec = 3M };
var V = Mapper.Map<IRequirement, Details>(D);
vard=新需求{PlanOct=1M,planov=2M,PlanDec=3M};
var V=映射器映射(D);
但事实并非如此(从存储库对象中提取单个域对象,然后使用实体框架从SQL Server提取):

var D=要求保存。要求(5);
var V=映射器映射(D);
根据以上所述,对于PlanQ1和PlanYear,我得到的结果都是0。我验证了域对象(D)中的PlanOct=1、PlanNov=2和PlanDec=3。我还验证了所有对象(包括EF生成的对象)中的类型都是decimal,SQL Server类型都是decimal。我甚至尝试映射到已创建的视图模型,只是为了排除这一点,但对于PlanQ1和PlanYear,我仍然得到0:

var D = requirementRepository.Requirement(5);
var V = new Details();
Mapper.Map<IRequirement, Details>(D, V);
var D=要求保存。要求(5);
var V=新的详细信息();
地图(D,V);

是否
PlanQ1
IRequirement
的成员?您在最后一段代码中暗示了这一点,但如果不是,则您将获得与您描述的完全相同的行为

考虑一个简单的例子,说明你正在做什么:

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]
公共空间地图()
{
CreateMap();
var foo1=new foo1(){Field1=“Field1”,Field2=“Field2”};
var foo2=新的foo2();
Mapper.Map(foo1,foo2);
Assert.AreEqual(“field1field2”,foo2.Field3);//失败,未映射
}

因此,如果我在
IFoo
Field3
中发表评论,一切都会重新开始。用你的代码检查这个简化的例子。

考虑@Wal post,试试这个地图

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

[TestMethod]
公共空间地图()
{
Mapper.CreateMap()
.ForMember(destination=>destination.Field3,options=>options.MapFrom(source=>source.Field1+source.Field2));
var foo1=new foo1(){Field1=“Field1”,Field2=“Field2”};
var foo2=新的foo2();
Mapper.Map(foo1,foo2);
Assert.AreEqual(“field1field2”,foo2.Field3);//True
}

刚刚意识到这是一个未回答的问题,所以我想结束它。从技术上讲,这是一个未回答的问题,因为出于某种原因,我无法让Automapper在这个场景中很好地发挥作用。最后我做的是返回并在我的存储库中创建两个映射方法,一个是将DAL对象的单个实例映射到iRequest然后在存储库中,我没有调用Mapper.map,而是调用我的自定义映射方法,它工作得非常好

我仍然不明白为什么这不起作用,但我遇到过其他几个类,Automapper刚刚抛出,我必须手动映射至少一个或两个字段,尽管在这些情况下Automapper会处理其余的字段


我肯定这其中有些东西我还没有看到。但无论如何,回到部分或完全手动映射是我的解决办法。

好的观点。不幸的是,是的PlanQ1和其他的在接口中定义为十进制PlanQ1{get;}。它失败了吗?因为它只定义了一个getter,而视图模型有一个getter和setter?没有。我刚刚添加了一个默认集{}对于接口,现在有一个域模型接口、域模型类和视图模型类的setter和getter。结果仍然为0.00。您最近的评论是描述我的示例-您的示例与我给出的示例有何不同?一定是有差异导致错误的beh
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; }
}
[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
}
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
}