Hi I'm trying to add to a model the property of colors color is an array of strings.
model
public class dog
{
// other properties
public ICollection<string> Colors { get; set; }
}
dbContext
public DataContext(DbContextOptions options) : base(options)
{
}
public DbSet<Dog> Dogs { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<AppUser>().HasMany(user => user.Dogs).WithOne(dog=> dog.AppUser)
.OnDelete(DeleteBehavior.Cascade);
}
What relation should I do if I want that if I delete a dog so the colors will be deleted as well? because I'm unable to run the migration because I'm getting this error:
The property 'dogs.Colors' could not be mapped because it is of type 'Collection', which is not a supported primitive type or a valid entity type. Either explicitly map this property, or ignore it using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'
I tried searching this question but I didn't really find any useful answers to my issue.
Can anyone please explain to me what causes it and what should I do to fix it?
CodePudding user response:
you can not use ICollection in your database Model becasue that doesn't have equivalent type in Database(such as sqlsever , mysql , ...)
actually you should create other table for 'Color' in this way :
public class dog
{
public int Id {get; set;}
// other properties
public ICollection<Color> Colors { get; set; }
}
public class Color
{
public string Value {get; set;}
public int DogId {get; set}
public dog Dog{ get; set; }
}
also you can add in your DbContext Class :
public DbSet<Color> Colors { get; set; }
Also if you don't want to save ICollection in database, you can ignore it using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'
For example :
[NotMapped]
public ICollection<string> Colors { get; set; }
CodePudding user response:
I'm thinking of two ways of handling this...
- Using a backing field as the following:
Backing fields allow EF to read and/or write to a field rather than a property. This can be useful when encapsulation in the class is being used to restrict the use of and/or enhance the semantics around access to the data by application code, but the value should be read from and/or written to the database without using those restrictions/enhancement
public class Dog
{
// other properties
private string _colors; //this is the backing field
public ICollection<string> Colors
{
get
{
if (string.IsNullOrWhiteSpace(_colors))
return new List<string>(); //empty list
return _colors.Split(",");
}
set
{
//you can have other logic, instead of setting it directly
//in this case it will overwrite the old value
_colors = string.Join(",", value);
}
}
}
On your database Dogs table, have a column name of Colors with nvarchar or varchar datatype.
When you store the color value, which is a list of string values, convert it to a concatenated single string value. Likewise, whenever you want to have the single string value on your code as a collection, use string to array conversion.
Re-model your Dog entity,
This will have you create two more tables on your database. These tables are Colors and DogsColors. One thing to note here is both Dog and Color have Many to Many relationship.
Depending on your dotnet core version, you may have to create one or more entity models.
If you are using Dotnet Core 5 or higher, you only need one entity model Color. Otherwise, you may have to also add the DogsColor entity model.
Dotnet core 5 or higher:
.net core 5 many to many relationships
Many to many relationships require a collection navigation property on both sides. They will be discovered by conventions like other types of relationships.
public class Color {
public int Id { get; set; }
public string Color { get; set;}
public ICollection<Dog> Dogs {get;set;} //for many to many relationship
}
public class Dog
{
public ICollection<Color> Colors { get; set; }
}
//dbcontext configuration
builder.Entity<Dog>()
.HasMany(i => i.Colors)
.WithMany(i => i.Dogs)
.UsingEntity<Dictionary<string, object>>(
"DogColors",
x => x.HasOne<Color>().WithMany().HasForeignKey("ColorId"),
x => x.HasOne<Dog>().WithMany().HasForeignKey("DogId"));
If you are using Dotnet core 3 or lower:
public class Color {
public int Id { get; set; }
public string Color { get; set;}
}
public class DogColor {
public int Id { get; set; }
public Dog Dog { get; set;}
public Color Color { get; set;}
}
public class Dog
{
public ICollection<DogColor> DogColors { get; set; }
}