简体   繁体   中英

How to create one-to-one mapping in EF from two tables to one source?

I want to have 2 models, for Example, "Person" and "Animal". both are modeled in the DB (postrge) with image_binary_id column.

    public class Person
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public ImageBinary ImageBinary { get; set; }
    }

    public class Animal
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public ImageBinary ImageBinary { get; set; }
    }

Now, I want the image data table will "provide" images for both objects, using the model:

    public class ImageBinary
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public byte[] Data { get; set; }
    }

In the DB, I have foreign keys connected "person.image_binary_id => image_binary.id"

How can I define the mapping in the code so the insert will be proper, in 1 transaction, like this:

var image = new ImageBinary(...);
var person = new Person() 
{
    ...,
    ImageBinary = image
}
PersonRepository.AddPerson(person);

I tried mapping the person it like this, but that causes the image_binary_id be null on insert:

entity.HasOne(x => x.ImageBinary)
   .WithOne()
   .HasForeignKey("ImageBinary", "Id");

I understand that if "ImageBinary" table will hold person \ animal columns, this might solve it since it will have "navigation" back (adding parameter to WithOne() )- but i dont want to add more columns (unless I have to...).

I thought about adding junction tables (person_id, image_binary_id) but that seems bad maintainability since I would have to add one for all future models as well.

Using .NET 5 with EF Core Version 5.

Any thoughts and solutions are welcome.

This is the the code first implementation of what you are trying to do.

public class Person
    {
        [Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public long Id { get; set; }
        public string Name { get; set; }
        
        public long ImageBinRef { get; set; }
        [ForeignKey("ImageBinRef")]
        //or [ForeignKey(nameof(ImageBinRef))] I like this version better
        public ImageBinary ImageBinary { get; set; }
    }

Here is some explanation of what I have done here

  • Key attribute tells Ef that Id is primary key

  • DatabaseGenerated(DatabaseGeneratedOption.Identity) tells ef that it's auto incremented

  • The ForeignKey attribute adds fk constraint and index to ImageBinRef property I have defined for you in my answer so the example you are trying to run will work now

one other important thing here is that your ImageBinary class' primary key is long type which is not nullable and does not accept null as a value. This is important because now when you delete a person record it will also delete the ImageBinary record connected to that (I do not know if this is what you want) if you dont want that record to be deleted simply declare the property like this

public long? ImageBinRef { get; set; } //Notice the question mark
    

the question mark means that it's a nullable type, so now when you delete the person record it will not delete the referenced image record..

note that strings are by default nullable therefore you do not need to worry about this:

say you have COUNTRIES table and PERSON table

public class PERSON{
   
 [Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
 public int PersonRowid {get;set:}
 public string PersonName {get;set:}

 public string PersonCountryCode {get;set;}

 [ForeignKey("PersonCountryCode")]
 public COUNTRIES Country {get;set;}
}

public class COUNTRIES{
   
 [Key]
 public string CountryCode {get;set:}
 public string CountryName {get;set:}
}

in this example when you delete a person the country record will still remain in the table, however if you change the property type of countrycode from string to int when you delete a person record it will also remove that country from the DB which probably is not something you want, to prevent these kind of scenarios we define our properties as nullable..

excuse if I made any typo, I have not used a compiler while adding the code samples.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM