我正在尝试将我的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属性,即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,*年和所有Variance *字段)都没有实际映射 - 它们都显示为默认值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
按照Wal的建议我运行了测试并且它工作正常,所以我开始一步一步地向后工作,首先将Field1 / Field2 / Field3部分粘贴到接口/域/视图模型类中并验证它是否有效我的控制器,然后一次改变一件事。我发现,因为我正在处理十进制类型,如果我硬编码整数或双值,那么我得到零,但如果我转换为十进制或使用十进制文字,那么它的工作原理。但是,只有我手动设置它们,而不是从数据库中提取值。
换句话说,这是有效的(即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);
但这不是(从存储库对象中提取单个域对象,而后者又使用Entity Framework从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);
答案 0 :(得分:2)
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]
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
}
因此,如果我在Field3
IFoo
发表评论,那么一切都会有效。用你的代码检查这个简化的例子。
答案 1 :(得分: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
}
答案 2 :(得分:1)
刚刚意识到这个没有答案,所以我想关闭它。从技术上讲,它没有答案,因为出于某种原因,我无法让Automapper在这种情况下发挥出色。我最后做的是返回并在我的存储库中创建几个映射方法,一个用于将DAL对象的单个实例映射到IRequirement对象,另一个用于映射集合。然后在存储库中而不是调用Mapper.Map我只是调用我的自定义映射方法,它完美地工作。
我仍然不明白为什么这不起作用,但我遇到了其他一些Automapper刚刚抛出的类,我必须手动映射至少一个或两个字段,尽管Automapper确实需要处理其余的那些情况。
我确定有一些关于它的东西我还没有看到。但无论如何,回到部分或完全手动映射是我的解决方法。