2

I have a table User and another table Company. A User can have a zero or one company registered.

User (1)---> (0..1) Company

My user class:

public class User {
    public string Id {get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public string FullName
    {
        get { return FirstName + " " + LastName; }
    }

    //Relations
    public virtual Company Company { get; set; }

}

and my company class is:

public class Company {
    public int Id { get; set; }        
    public string CompanyName { get; set; }
    public string TaxNumber { get; set; }
    public string TaxOffice { get; set; }
    public string OfficeTel { get; set; }
    public string FaxNumber { get; set; }
    public string WebSite { get; set; }
    public string Address { get; set; }
    public string About { get; set; }

    //keys
    public int CityId { get; set; }
    public int StateId { get; set; }                
    public string UserId { get; set; }

    //relations
    public City City { get; set; }
    public State State { get; set; }        
    public User User { get; set; }
}

the fluent api used for company is like this:

public class CompanyConfiguration : EntityTypeConfiguration<Company>
{
    public CompanyConfiguration()
    {
        this.HasRequired(x => x.User)
            .WithOptional(x => x.Company);

        this.HasRequired(x => x.City)
            .WithMany(x => x.Companies).HasForeignKey(x => x.CityId).WillCascadeOnDelete(false);

        this.HasRequired(x => x.State)
            .WithMany(x => x.Companies).HasForeignKey(x => x.StateId).WillCascadeOnDelete(false);

        this.Property(x => x.Address).HasMaxLength(400);
        this.Property(x => x.CompanyName).HasMaxLength(100).IsRequired();
        this.Property(x => x.FaxNumber).HasMaxLength(20);
        this.Property(x => x.OfficeTel).HasMaxLength(20);
        this.Property(x => x.TaxNumber).HasMaxLength(20).IsRequired();
        this.Property(x => x.TaxOffice).HasMaxLength(50).IsRequired();
        this.Property(x => x.WebSite).HasMaxLength(200);            
    }
}

After I run Add-Migration what I expect is that UserId used as foreign key for User in Company table, but what is generated by Entity framework migrations is:

CreateTable(
            "dbo.Companies",
            c => new
                {
                    Id = c.Int(nullable: false, identity: true),
                    CompanyName = c.String(nullable: false, maxLength: 100),
                    TaxNumber = c.String(nullable: false, maxLength: 20),
                    TaxOffice = c.String(nullable: false, maxLength: 50),
                    OfficeTel = c.String(maxLength: 20),
                    FaxNumber = c.String(maxLength: 20),
                    WebSite = c.String(maxLength: 200),
                    Address = c.String(maxLength: 400),
                    About = c.String(),
                    CityId = c.Int(nullable: false),
                    StateId = c.Int(nullable: false),
                    UserId = c.String(),
                    User_Id = c.String(nullable: false, maxLength: 128),
                })
            .PrimaryKey(t => t.Id)
            .ForeignKey("dbo.Cities", t => t.CityId)
            .ForeignKey("dbo.States", t => t.StateId)
            .ForeignKey("dbo.AspNetUsers", t => t.User_Id)
            .Index(t => t.CityId)
            .Index(t => t.StateId)
            .Index(t => t.User_Id);

Question is how can I force Entity Framework to use my specified property as foreign key for relation, and the reason for this is I need the userId value of a company frequently in my code, and I don't want to use Company.User.Id expression to get that.

Note: I use Entity Framework 6.1.2 and asp.net mvc 5

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
mesut
  • 2,099
  • 3
  • 23
  • 35
  • I'm not sure it makes a difference, but is the `Id` (or `UserId`, I'm not sure) field in the `AspNetUsers` table defined as having `MaxLength(128)`? The auto-gen'd field has that restriction. Makes me wonder if a mismatch there makes a difference. – Tim Apr 14 '15 at 20:27
  • @Tim, the user table is asp.net Identity 2's autogenerated table for Identity user and I didn't make change at it. – mesut Apr 14 '15 at 20:30
  • I realize that. I don't have one handy to look at. You created your UserId field (on Company, that you intend to be the FK) w/o a MaxLength. I'm wondering if there is a mismatch between that and what's in the (default) AspNetUsers table. – Tim Apr 14 '15 at 20:32
  • 1
    I don't get your domain model, a user may have 0 - 1 comapny. but your comapny model has one user? surely that should be a list of users. – Jed I Apr 14 '15 at 20:37
  • should you company model hav something like this ? public virtual ICollection users { get; set; } – Jed I Apr 14 '15 at 20:40
  • @Tim as default entity framework creates columns for a relation name (here is user) and a "Id" or "_Id" after that by conventions. ıf I add maxlength constraint to the company entity configuration, nothing will change, the problem is not that, the problem is with entity framework that not recognize that the "UserId" field can be foriegn key for "User" Relation. and there is no a function like HasForiegnKey() when using one-to-one or one-to-zeroOrOne relation to give me chance to define it manually. – mesut Apr 14 '15 at 20:48
  • @JedI, I think you missunderstand the one-to-one and one-to-zero or one relation. One Company has only and only one User associated with. and one user can have zero or just one company. – mesut Apr 14 '15 at 20:50
  • that's an odd requirement. I think i remember reading somewhere about the 1 to 1 issue. and it was suggested to merge the two models, http://stackoverflow.com/questions/9687980/why-use-a-1-to-1-relationship-in-database-design . hope this helps – Jed I Apr 14 '15 at 21:00

2 Answers2

0

Here is how I would define the foreignkey in this relationship:

public class Company {
   public int Id { get; set; }        

   [Required]
   [Key, ForeignKey("User")]
   public string UserId { get; set; }       

   public User User { get; set; }
}
renakre
  • 8,001
  • 5
  • 46
  • 99
  • 1
    Thank you for reply; but I cannot change the model, that is too late to do that. we need a way to specify foreign key in fluent api. – mesut Apr 15 '15 at 07:34
  • @mesut `how can I force Entity Framework to use my specified property as foreign key for relation,` this requires a model change whether you use data annotations or fluent api? – renakre Apr 15 '15 at 12:45
  • 1
    but I can use HasForiegnKey function with other relation types, why just one to one relation needs the model change? – mesut Apr 15 '15 at 12:50
0

A bit late to the party but just throwing my thoughts in in-case anyone else comes across this question.

Had the same problem myself, Entity framework (EF6) does not seem to have a baked in way of specifying the foreign key for a 1-2-0/1 relationship, however its important to remember it is designed to be overwritten if required. The only way I could configure this was to manually amend the auto-generated migration file.

Example below is an abbreviated version of the auto-generated migration code (as posted above) showing the UserId that was intended to be the FK and the automatically added property User_Id that was inserted by EF to be the FK

    CreateTable(
        "dbo.Companies",
        c => new
            {
                Id = c.Int(nullable: false, identity: true),
                ...
                UserId = c.String(),
                User_Id = c.String(nullable: false, maxLength: 128),
            })
        .PrimaryKey(t => t.Id)
        ...
        .ForeignKey("dbo.AspNetUsers", t => t.User_Id)
        ...
        .Index(t => t.User_Id);

To achieve the original intention of the UserId being the FK, simply delete the autogenerated property then amend the FK statement and the index statement

    CreateTable(
        "dbo.Companies",
        c => new
            {
                Id = c.Int(nullable: false, identity: true),
                ...
                UserId = c.String(nullable: false, maxLength: 128),

            })
        .PrimaryKey(t => t.Id)
        ....
        .ForeignKey("dbo.AspNetUsers", t => t.UserId)
        ...
        .Index(t => t.UserId);

NB The Down method to revert the Migration is not shown in the question but any additions or amendments made to the Up method need to be reflected in the Down method as well.

Scheeeve
  • 65
  • 7