Marty Carr
Marty Carr

Reputation: 37

Setting up an Entity Framework object that contains a collection

My Customer class contains a collection of my Card class. I'm not exactly sure how to express this relationship to Entity Framework.

I get the following error:

No suitable constructor found for entity type 'Card'. The following constructors had parameters that could not be bound to properties of the entity type: cannot bind 'id', 'cardBrand', 'last4', 'expMonth', 'expYear', 'cardholderName', 'billingAddress', 'fingerprint', 'cardType', 'prepaidType', 'bin' in 'Card(string id, string cardBrand, string last4, Nullable expMonth, Nullable expYear, string cardholderName, Address billingAddress, string fingerprint, string cardType, string prepaidType, string bin)'.

Customer class:

public class Customer
{
    public Customer(string id = null, string createdAt = null, string updatedAt = null, IList<Card> cards = null, string givenName = null, string familyName = null, string nickname = null, string companyName = null, string emailAddress = null, Address address = null, string phoneNumber = null, string birthday = null, string referenceId = null, string note = null, CustomerPreferences preferences = null, IList<CustomerGroupInfo> groups = null, string creationSource = null, IList<string> groupIds = null, IList<string> segmentIds = null);

    [JsonProperty("group_ids", NullValueHandling = NullValueHandling.Ignore)]
    public IList<string> GroupIds { get; }
    [JsonProperty("creation_source", NullValueHandling = NullValueHandling.Ignore)]
    public string CreationSource { get; }
    [JsonProperty("groups", NullValueHandling = NullValueHandling.Ignore)]
    public IList<CustomerGroupInfo> Groups { get; }
    [JsonProperty("preferences", NullValueHandling = NullValueHandling.Ignore)]
    public CustomerPreferences Preferences { get; }
    [JsonProperty("note", NullValueHandling = NullValueHandling.Ignore)]
    public string Note { get; }
    [JsonProperty("reference_id", NullValueHandling = NullValueHandling.Ignore)]
    public string ReferenceId { get; }
    [JsonProperty("birthday", NullValueHandling = NullValueHandling.Ignore)]
    public string Birthday { get; }
    [JsonProperty("phone_number", NullValueHandling = NullValueHandling.Ignore)]
    public string PhoneNumber { get; }
    [JsonProperty("address", NullValueHandling = NullValueHandling.Ignore)]
    public Address Address { get; }
    [JsonProperty("email_address", NullValueHandling = NullValueHandling.Ignore)]
    public string EmailAddress { get; }
    [JsonProperty("company_name", NullValueHandling = NullValueHandling.Ignore)]
    public string CompanyName { get; }
    [JsonProperty("nickname", NullValueHandling = NullValueHandling.Ignore)]
    public string Nickname { get; }
    [JsonProperty("family_name", NullValueHandling = NullValueHandling.Ignore)]
    public string FamilyName { get; }
    [JsonProperty("given_name", NullValueHandling = NullValueHandling.Ignore)]
    public string GivenName { get; }
    [JsonProperty("cards", NullValueHandling = NullValueHandling.Ignore)]
    public IList<Card> Cards { get; }
    [JsonProperty("updated_at", NullValueHandling = NullValueHandling.Ignore)]
    public string UpdatedAt { get; }
    [JsonProperty("created_at", NullValueHandling = NullValueHandling.Ignore)]
    public string CreatedAt { get; }
    [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)]
    public string Id { get; }
    [JsonProperty("segment_ids", NullValueHandling = NullValueHandling.Ignore)]
    public IList<string> SegmentIds { get; }

    public override bool Equals(object obj);
    public override int GetHashCode();
    public Builder ToBuilder();
    public override string ToString();
    protected void ToString(List<string> toStringOutput);

    public class Builder
    {
        public Builder();

        public Builder Address(Address address);
        public Builder Birthday(string birthday);
        public Customer Build();
        public Builder Cards(IList<Card> cards);
        public Builder CompanyName(string companyName);
        public Builder CreatedAt(string createdAt);
        public Builder CreationSource(string creationSource);
        public Builder EmailAddress(string emailAddress);
        public Builder FamilyName(string familyName);
        public Builder GivenName(string givenName);
        public Builder GroupIds(IList<string> groupIds);
        public Builder Groups(IList<CustomerGroupInfo> groups);
        public Builder Id(string id);
        public Builder Nickname(string nickname);
        public Builder Note(string note);
        public Builder PhoneNumber(string phoneNumber);
        public Builder Preferences(CustomerPreferences preferences);
        public Builder ReferenceId(string referenceId);
        public Builder SegmentIds(IList<string> segmentIds);
        public Builder UpdatedAt(string updatedAt);
    }
}

My card class:

public class Card
{
    public Card(string id = null, string cardBrand = null, string last4 = null, long? expMonth = null, long? expYear = null, string cardholderName = null, Address billingAddress = null, string fingerprint = null, string cardType = null, string prepaidType = null, string bin = null);

    [JsonProperty("prepaid_type", NullValueHandling = NullValueHandling.Ignore)]
    public string PrepaidType { get; }
    [JsonProperty("card_type", NullValueHandling = NullValueHandling.Ignore)]
    public string CardType { get; }
    [JsonProperty("fingerprint", NullValueHandling = NullValueHandling.Ignore)]
    public string Fingerprint { get; }
    [JsonProperty("billing_address", NullValueHandling = NullValueHandling.Ignore)]
    public Address BillingAddress { get; }
    [JsonProperty("cardholder_name", NullValueHandling = NullValueHandling.Ignore)]
    public string CardholderName { get; }
    [JsonProperty("exp_year", NullValueHandling = NullValueHandling.Ignore)]
    public long? ExpYear { get; }
    [JsonProperty("exp_month", NullValueHandling = NullValueHandling.Ignore)]
    public long? ExpMonth { get; }
    [JsonProperty("last_4", NullValueHandling = NullValueHandling.Ignore)]
    public string Last4 { get; }
    [JsonProperty("card_brand", NullValueHandling = NullValueHandling.Ignore)]
    public string CardBrand { get; }
    [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)]
    public string Id { get; }
    [JsonProperty("bin", NullValueHandling = NullValueHandling.Ignore)]
    public string Bin { get; }

    public override bool Equals(object obj);
    public override int GetHashCode();
    public Builder ToBuilder();
    public override string ToString();
    protected void ToString(List<string> toStringOutput);

    public class Builder
    {
        public Builder();

        public Builder BillingAddress(Address billingAddress);
        public Builder Bin(string bin);
        public Card Build();
        public Builder CardBrand(string cardBrand);
        public Builder CardholderName(string cardholderName);
        public Builder CardType(string cardType);
        public Builder ExpMonth(long? expMonth);
        public Builder ExpYear(long? expYear);
        public Builder Fingerprint(string fingerprint);
        public Builder Id(string id);
        public Builder Last4(string last4);
        public Builder PrepaidType(string prepaidType);
    }
}

Upvotes: 0

Views: 61

Answers (1)

Harald Coppoolse
Harald Coppoolse

Reputation: 30454

Entity Framework classes: POCO only!

The problem is that your types don't have a default constructor, just like the error says.

When using entity framework, the classes represent your tables and the relations between the tables. They should be simple POCOs (plain old CRL object). So:

  • No constructor
  • No fields
  • Only get / set properties
  • Preferably no Methods, after all: the class represents your table, the table doesn't have any methods

See POCO classes in entity framework

This tutorial helped me a lot to understand how to use entity framework

One-to-many in entity framework

So you want to create a one-to-many relation between Customers and Cards: every Customer has zero or more Cards, every Card belongs to exactly one Customer.

In entity framework you would model this using the following classes:

public class Customer
{
    public int Id {get; set;}
    public string Name {get; set;}
    ...

    // Every Customer has zero or more Cards (one-to-many)
    public virtual ICollection<Card> Cards {get; set;}
}

public class Card
{
    public int Id {get; set;}
    public string Name {get; set;}
    ...

    // Every Card is a Card of exactly one Customer, using foreign key:
    public int CustomerId {get; set;}
    public virtual Customer Customer {get; set;}
}

And of course the DbContext:

public class CustomerDbContext : DbContext
{
    public DbSet<Customer> Customers {get; set;}
    public DbSet<Card> Cards {get; set;}
}

Because I followed the entity framework conventions, especially those about plurifications and the virtual ICollections, Entity framework automatically detects the tables, the columns in the tables and the one-to-many relation.

In entity framework the columns of the tables are represented by non-virtual properties. The virtual properties represent the relations between the tables (one-to-many, many-to-many).

The foreign key CustomerId is a real column in table Cards, hence it it not virtual Cards.Customer is not a column, it represents the relation between Card and Customer, hence it is virtual

By the way: I made it a virtual ICollection<Card>, not some kind of List, because Card[4] wouldn't have a defined meaning after fetching data, while ICollection methods like Add / Remove do have defined meanings.

Only if I want to deviate from the conventions: different table names, or different identifiers for the columns, or their types, some Attributes of fluent API is needed.

Still, if you want to specify the one-to-many relation as fluent API in DbContext.OnModelCreating, use the following:

// Every Customer has zero or more Cards, using foreign key (one-to-many)
modelBuilder.Entity<Customer>().HasMany(customer => customer.Cards)
    .WithRequired(card => card.Customer)
    .HasForeignKey(card => card.CustomerId);

In words: every Customer in table Customers has zero or more Cards, via property Customer.Cards. Every Card belongs to exactly one Customer via property Card.Customer. In the database this is forced using foreign key Card.CustomerId.

Upvotes: 1

Related Questions