2014-12-22 5 views
2

Я впервые рассмотрел Automapper, используя F # и Provider Entity Type. Я хочу сопоставить типы типов поставщиков EF и типы записей F #, которые я создал.Использование Automapper с провайдером Entity Type F #

ЭФ Тип поставщика основан на следующей схеме базы данных:

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 

мне интересно, если это б/с EF является отложенной загрузки, так что остальные типы не будучи ева luated? Кто-нибудь видел это раньше?

+0

Могу ли я рекомендовать демпинг AutoMapper с панели инструментов, если вы заботитесь о чувственных типов в ваших программах. –

+0

бит старый, но что произойдет, если вы не используете список FSharp и используете массив в своих определениях записи. Вещи могут начать работать, поскольку массив - это не определенный тип F #. –

+1

@GregC Альтернатива - это написать код. Это лучше, потому что компилятор может проверять вещи, и вы можете рассуждать о своем коде. Другой альтернативой были бы макросы времени компиляции, но это еще не очень хорошо поддерживается в .NET. –

ответ

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} 
+0

Это привело меня от 1 ошибки к следующей: AutoMapper.AutoMapperMappingException: Отсутствует конфигурация карты типа или неподдерживаемое отображение. Типы сопоставления: EntityCollection'1 -> FSharpList'1 –

Смежные вопросы