将Automapper与F#实体类型提供程序一起使用

时间:2014-12-22 15:19:46

标签: entity-framework f# automapper f#-data

我首次使用F#和实体类型提供程序查看Automapper。我想在EF类型提供程序类型和我创建的F#记录类型之间进行映射。

EF类型提供程序基于以下数据库架构:

CREATE TABLE [dbo].[Address](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [FamilyId] [int] NOT NULL,
    [State] [varchar](50) NOT NULL,
    [County] [varchar](50) NOT NULL,
    [City] [varchar](50) NOT NULL,
    CONSTRAINT [PK_Address] PRIMARY KEY CLUSTERED ([Id] ASC)
CREATE TABLE [dbo].[Child](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [FamilyId] [int] NOT NULL,
    [FirstName] [varchar](50) NOT NULL,
    [Gender] [varchar](50) NOT NULL,
    [Grade] [int] NOT NULL,
    CONSTRAINT [PK_Child] PRIMARY KEY CLUSTERED ([Id] ASC)
CREATE TABLE [dbo].[Family](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [LastName] [varchar](50) NOT NULL,
    [IsRegistered] [bit] NOT NULL,
    CONSTRAINT [PK_Family] PRIMARY KEY CLUSTERED ([Id] ASC)
CREATE TABLE [dbo].[Parent](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [FamilyId] [int] NOT NULL,
    [FirstName] [varchar](50) NOT NULL,
    CONSTRAINT [PK_Parent] PRIMARY KEY CLUSTERED ([Id] ASC)
CREATE TABLE [dbo].[Pet](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [ChildId] [int] NOT NULL,
    [GivenName] [varchar](50) NOT NULL,
    CONSTRAINT [PK_Pet] PRIMARY KEY CLUSTERED ([Id] ASC)
ALTER TABLE [dbo].[Address]  WITH CHECK ADD  CONSTRAINT [FK_Address_Family] FOREIGN KEY([FamilyId])
REFERENCES [dbo].[Family] ([Id])
ALTER TABLE [dbo].[Address] CHECK CONSTRAINT [FK_Address_Family]
ALTER TABLE [dbo].[Child]  WITH CHECK ADD  CONSTRAINT [FK_Child_Family] FOREIGN KEY([FamilyId])
REFERENCES [dbo].[Family] ([Id])
ALTER TABLE [dbo].[Child] CHECK CONSTRAINT [FK_Child_Family]
ALTER TABLE [dbo].[Parent]  WITH CHECK ADD  CONSTRAINT [FK_Parent_Family] FOREIGN KEY([FamilyId])
REFERENCES [dbo].[Family] ([Id])
ALTER TABLE [dbo].[Parent] CHECK CONSTRAINT [FK_Parent_Family]
ALTER TABLE [dbo].[Pet]  WITH CHECK ADD  CONSTRAINT [FK_Pet_Child] FOREIGN KEY([ChildId])
REFERENCES [dbo].[Child] ([Id])
ALTER TABLE [dbo].[Pet] CHECK CONSTRAINT [FK_Pet_Child]

然后我在F#中创建了一组类似的类型:

type Pet = {Id:int; GivenName:string}
type Child = {Id:int; FirstName:string; Gender:string; Grade:int; Pets: Pet list}
type Address = {Id:int; State:string; County:string; City:string}
type Parent = {Id:int; FirstName:string}
type Family = {Id:int; Parents:Parent list; Children: Child list; Address:Address}

唯一真正的区别是外键在记录类型中不明确。

当我在地址类型上使用Automapper时,它按预期工作:

Mapper.CreateMap<EntityConnection.ServiceTypes.Address, Address>()
let context  = EntityConnection.GetDataContext()
let addressQuery = query {for address in context.Addresses do select address}
let address = Seq.head addressQuery
let address' = Mapper.Map<Address>(address)

val address' : Address = {Id = 1;
                          State = "WA";
                          County = "King";
                          City = "Seattle";}

但是当我尝试对整个图表做同样的事情时,

Mapper.CreateMap<EntityConnection.ServiceTypes.Pet, Pet>()
Mapper.CreateMap<EntityConnection.ServiceTypes.Child, Child>()
Mapper.CreateMap<EntityConnection.ServiceTypes.Address, Address>()
Mapper.CreateMap<EntityConnection.ServiceTypes.Parent, Parent>()
Mapper.CreateMap<EntityConnection.ServiceTypes.Family, Family>()

let context  = EntityConnection.GetDataContext()
let familyQuery = query {for family in context.Families do select family}
let family = Seq.head familyQuery

let family' = Mapper.Map<Family>(family)

我得到了这个例外:

System.ArgumentException: Type needs to have a constructor with 0 args or only optional args
Parameter name: type

我想知道它是否是b / c EF是延迟加载所以剩下的类型没有被评估?有没有人见过这个?

1 个答案:

答案 0 :(得分:2)

错误很简单。没有一个类有一个带0参数的构造函数。

F#为您创建默认构造函数,因此类中的默认构造函数中包含多个参数。例如:

type Pet = {Id:int; GivenName:string}

作为一个c#类会有这个定义。

public class Pet
{
    public int Id { get; private set; }
    public string GivenName { get; private set; }
    public Pet(int id, string givenName)
    {
        Id = id;
        GivenName = givenName;
    }
}

注意缺少无参数构造函数。这就是你的错误来自的地方。

您可以通过将类型标记为CLIMutable

来解决此问题
[<CLIMutable>]
type Pet = {Id:int; GivenName:string}