modelBuilder.Configurations.Add and modelBuilder.Entity on OnModelCreating - c#

I have just started working on entity framework code first approach, I have written two approaches below and both are working fine.
Please let me know what are the core concepts behind both these approaches and what should follow?
Approach 1 : Using EntityTypeConfiguration
public class BlogsMap : EntityTypeConfiguration<Blog>
{
public BlogsMap(string schema)
{
ToTable("BLOG");
HasKey(t => t.BlogId);
Property(t => t.BlogId).HasColumnName("BLOGID");
Property(t => t.Name).HasColumnName("NAME");
Property(t => t.Url).HasColumnName("URL");
}
}
public class BlogContext : DbContext
{
public BlogContext(string name)
: base(name)
{
}
public IDbSet<Blog> BLOG { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new BlogMap(string.Empty));
}
}
Approach 2 :
public class Blog
{
public int BlogId { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public virtual List<Post> Posts { get; set; }
}
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>();
}
}
Please provide me concept/blogs on entity,since i have just started.

You have several ways to configure your entities. Below I will show three ways,one using DataAnnotations and two using Fluent Api.
The first variant is using DataAnnotations. You can use attributes(DataAnnotations) to configure your entity classes and properties.DataAnnotations attributes overrides default Code First conventions:
[Table(“BLOGS”)]
public class Blog
{
[Key]
[Column(“BLOGID”)]
public int BlogId { get; set; }
[Column(“NAME”)]
public string Name { get; set; }
[Column(“URL”)]
public string Url { get; set; }
public virtual List<Post> Posts { get; set; }
}
[Table(“POSTS”)]
public class Post
{
[Key]
[Column(“POSTID”)]
public int PostId { get; set; }
[Column(“TEXT”)]
public string Text { get; set; }
public int BlogId { get; set; }
[ForeignKey("BlogId")]
public virtual BaseCard Blog { get; set; }
}
Then, in your context class, you don’t need to override the OnModelCreating method, EF will use the attribute to map your entities and relationship (it will create a 1-to-many relationship between blog and post):
public class BlogContext : DbContext
{
public BlogContext(string name)
: base(name)
{
}
public IDbSet<Blog> Blogs { get; set; }
public IDbSet<Post> Posts { get; set; }
}
Configuring with Data Annotations is fairly simple and it may be just what you’re looking for. But Data Annotations only allow you to access a subset of the possible configurations (though much more than you’ve seen so far). The Fluent API , however, gives you access to even more, so you may prefer it for this reason.
With Fluent Api you don’t need to use attributes to map your fields and relationships of your entities classes. There are two ways to use Fluent Api:
1-Mapping the entities (fields and relationships) in the OnModelCreating method in your context (Your second Aproach):
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>().ToTable("BLOGS");
modelBuilder.Entity<Blog>().HasKey(t => t.BlogId);
modelBuilder.Entity<Blog>().Property(t => t.BlogId).HasColumnName("BLOGID");
modelBuilder.Entity<Blog>().Property(t => t.Name).HasColumnName("NAME");
modelBuilder.Entity<Blog>().Property(t => t.Url).HasColumnName("URL");
// The same with post
//mapping one-to-many relationship
modelBuilder.Entity<Post>().HasRequired(c => c.Blog)
.WithMany(s => s.Posts)
.HasForeignKey(c => c.BlogId);
}
2-The second variant using Fluent Api is creating mapping classes (Your First Approach). This way, you configure your Entities in classes that inherit of EntityTypeConfiguration<TEntity>:
public class BlogMap : EntityTypeConfiguration<Blog>
{
public BlogMap()
{
ToTable("BLOGS");
HasKey(t => t.BlogId);
Property(t => t.BlogId).HasColumnName("BLOGID");
Property(t => t.Name).HasColumnName("NAME");
Property(t => t.Url).HasColumnName("URL");
}
}
public class PostMap : EntityTypeConfiguration<Post>
{
public PostMap()
{
ToTable("POSTS");
HasKey(t => t.PostId);
Property(t => t.Text).HasColumnName("TEXT");
//mapping the relationship
HasRequired(c => c.Blog)
.WithMany(s => s.Posts)
.HasForeignKey(c => c.BlogId);
}
}
Then, to include the mappings in your context you need to add them in the OnModelCreating method:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new BlogMap());
modelBuilder.Configurations.Add(new PostMap());
}
The best way to add the configurations is at this way:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
var typesToRegister = Assembly.GetExecutingAssembly().GetTypes()
.Where(type => !String.IsNullOrEmpty(type.Namespace))
.Where(type => type.BaseType != null && type.BaseType.IsGenericType
&& type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>));
foreach (var type in typesToRegister)
{
dynamic configurationInstance = Activator.CreateInstance(type);
modelBuilder.Configurations.Add(configurationInstance);
}
base.OnModelCreating(modelBuilder);
}
This last variant (the first approach) for me is the best due to you don’t have to touch your model classes (adding attributes) to specify what you want and is more flexible if you want to add a new entity or change something.

string nspace = "CompanyAdministration.data.Models";
var q = from t in Assembly.GetExecutingAssembly().GetTypes()
where t.IsClass && t.Namespace == nspace && t.Name[0] != '<' && t.Name.Substring(0, 2) != "BOX" && t.Name != "CAContext"
select t;
foreach (Type t in q)
{
try
{
MethodInfo method = modelBuilder.GetType().GetMethod("Entity");
method = method.MakeGenericMethod(new Type[] { t });
method.Invoke(modelBuilder, null);
}
catch
{
}
}
base.OnModelCreating(modelBuilder);

Related

One to many in Ef core Fk Viloation

Ok I think I may have got this wrong in the model builder. I want the case which can be one case but inside that one case they can be many relationships.
modelBuilder.Entity<RelationShips>()
.HasOne<MISObject>(s => s.Case)
.WithMany(g => g.RelationShip)
.HasForeignKey(s => s.MisObjectId);
But when I attempt to save with the above
DbUpdateException: An error occurred while updating the entries. See
the inner exception for details. SqlException: The INSERT statement
conflicted with the FOREIGN KEY constraint
"FK_RelationShips_MISobject_MisObjectId". The conflict occurred in
database "MISSystem", table "dbo.MISobject", column 'Id'. The
statement has been terminated.
My MISObject has a collection of relationships as such
public class MISObject {
public int Id { get; set; }
public ICollection<RelationShips> RelationShip { get; set; }
}
public class RelationShips {
public int Id { get; set; }
public MISObject Case { get; set; }
}
Will the above not allow a one to many relationship basically one case could have 20 relationships but there could be many cases. But those 20 relationships should only belong to that case if that makes since.
I think I need to use hasmany but not to sure how in this context.
Edit 2
I think this might be what i need but im not sure how legal it is.
modelBuilder.Entity<MISObject>()
.HasMany(c => c.RelationShip);
modelBuilder.Entity<RelationShips>()
.HasMany(c => c.PersonOfIntrests);
modelBuilder.Entity<POI>()
.HasMany(c => c.PersonOfIntrestsPhotos)
.WithOne(e => e.PersonOfIntrest);
To make this work with the FluentAPI, you need to completely define the navigation and use a foreign key:
public class Relationship {
public int Id { get; set; }
public int MisObjectId { get; set; } // <-- add foreign key ID
public MisObject Case { get; set; }
}
public class Context : DbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MisObject>()
.HasMany(o => o.Relationships)
.WithOne(r => r.Case) // <-- add other endpoint
.HasForeignKey(r => r.MisObjectId); // <-- add FK property
}
}
Here is a fully working console project, that demonstrates these concepts:
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace IssueConsoleTemplate
{
public class MisObject {
public int Id { get; set; }
public ICollection<Relationship> Relationships { get; set; }
}
public class Relationship {
public int Id { get; set; }
public int MisObjectId { get; set; } // <-- add foreign key ID
public MisObject Case { get; set; }
}
public class Context : DbContext
{
public DbSet<MisObject> MisObjects { get; set; }
public DbSet<Relationship> Relationships { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(#"Data Source=.\MSSQL14;Integrated Security=SSPI;Initial Catalog=So62854210")
.UseLoggerFactory(
LoggerFactory.Create(
b => b
.AddConsole()
.AddFilter(level => level >= LogLevel.Information)))
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MisObject>()
.HasMany(o => o.Relationships)
.WithOne(r => r.Case) // <-- add other endpoint
.HasForeignKey(r => r.MisObjectId); // <-- add FK property
// Technically not necessary, because this navigation has already been defined
// in the previous line, but might be good practice anyway.
modelBuilder.Entity<Relationship>()
.HasOne(r => r.Case)
.WithMany(o => o.Relationships)
.HasForeignKey(r => r.MisObjectId);
}
}
internal static class Program
{
private static void Main()
{
using (var context = new Context())
{
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
var newMisObject = new MisObject();
var newRelationships = new[]
{
new Relationship {Case = newMisObject},
new Relationship {Case = newMisObject},
new Relationship {Case = newMisObject},
};
context.MisObjects.Add(newMisObject);
context.Relationships.AddRange(newRelationships);
context.SaveChanges();
}
using (var context = new Context())
{
var misObjects = context.MisObjects
.Include(o => o.Relationships)
.ToList();
Debug.Assert(misObjects.Count == 1);
Debug.Assert(misObjects[0].Relationships.Count == 3);
}
}
}
}
Coincidentally, because the properties in this example follow EF Core naming conventions, you could even remove the OnModelCreating() method entirely here and the result would still work.
See Relationships: Conventions for further information on that.
Just use convention there is no need to use fluent config for relationships:
public class MISObject
{
public int Id { get; set; }
public ICollection<RelationShips> RelationShip { get; set; }
}
public class RelationShips
{
public int Id { get; set; }
public int CaseId { get; set; }
public MISObject Case { get; set; }
}
without any error, EF Core makes your Tables in the database.

how to apply common configuration to all entities in ef core

I have entities derived from a base entity in my application which uses ef core code-first approach.
Base class
public abstract class BaseEntity<T> : IEntity<T>
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public T Id { get; set; }
object IEntity.Id { get { return Id; } set { } }
private DateTime? createdOn;
[DataType(DataType.DateTime)]
public DateTime CreatedOn { get => createdOn ?? DateTime.Now; set => createdOn = value; }
[DataType(DataType.DateTime)]
public DateTime? ModifiedOn { get; set; }
public bool IsDeleted { get; set; }
// Auto increment for all entities.
public int OrderId { get; set; }
}
And an entity
public class UserEntity : BaseEntity<int>
{
public string EmployeeId { get; set; }
public string FullName { get; set; }
public string Email { get; set; }
}
I can apply the .ValueGeneratedOnAdd() method on property OrderId in OnModelCreating for each entity however, is there a way to apply a general rule for all entities without repeatig yourself?
With the lack of custom conventions, you could use the typical modelBuilder.Model.GetEntityTypes() loop, identify the target entity types and invoke common configuration.
Identification in your case is a bit complicated because of the base generic class, but doable by iterating down Type.BaseType and check for BaseEntity<>. Once you find it, you can retrieve the generic argument T which you'll need later.
If you don't want to use generic class implementing IEnityTypeConfiguration<TEntity>, then the idea is to put the implementation in generic constrained method like this
static void Configure<TEntity, T>(ModelBuilder modelBuilder)
where TEntity : BaseEntity<T>
{
modelBuilder.Entity<TEntity>(builder =>
{
builder.Property(e => e.OrderId).ValueGeneratedOnAdd();
});
}
Passing the actual entity type TEntity to modelBuilder.Enity method is crucial, because otherwise EF Core will consider whatever you pass to be an entity type and configure TPH inheritance.
Calling the method requires reflection - finding the generic method definition, using MakeGenericMethod and then Invoke.
Here is all that encapsulated in a static class:
public static class BaseEntityConfiguration
{
static void Configure<TEntity, T>(ModelBuilder modelBuilder)
where TEntity : BaseEntity<T>
{
modelBuilder.Entity<TEntity>(builder =>
{
builder.Property(e => e.OrderId).ValueGeneratedOnAdd();
});
}
public static ModelBuilder ApplyBaseEntityConfiguration(this ModelBuilder modelBuilder)
{
var method = typeof(BaseEntityConfiguration).GetTypeInfo().DeclaredMethods
.Single(m => m.Name == nameof(Configure));
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
if (entityType.ClrType.IsBaseEntity(out var T))
method.MakeGenericMethod(entityType.ClrType, T).Invoke(null, new[] { modelBuilder });
}
return modelBuilder;
}
static bool IsBaseEntity(this Type type, out Type T)
{
for (var baseType = type.BaseType; baseType != null; baseType = baseType.BaseType)
{
if (baseType.IsGenericType && baseType.GetGenericTypeDefinition() == typeof(BaseEntity<>))
{
T = baseType.GetGenericArguments()[0];
return true;
}
}
T = null;
return false;
}
}
Now all you need is to call it from inside your OnModelCreating override:
modelBuilder.ApplyBaseEntityConfiguration();
In EF6 you can use:
modelBuilder.Properties<int>().Where(p=>p.Name == "OrderId").Configure(c => c.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity));
foreach (var item in modelBuilder.Model.GetEntityTypes())
{
item.FindProperty("CreatedOn")?.SetDefaultValueSql("GETDATE()");
item.FindProperty("ModifiedOn")?.SetDefaultValueSql("GETDATE()");
item.FindProperty("AAStatus")?.SetDefaultValue("Alive");
}
i researched and found this thread, my solution after reading it is
If you want every property named OrderId to be ValueGeneratedOnAddYou you could solve it like this without repeating yourself:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
foreach (var et in modelBuilder.Model.GetEntityTypes())
{
foreach (var prop in et.GetProperties())
{
if (prop.Name == "OrderId")
{
prop.ValueGenerated = Microsoft.EntityFrameworkCore.Metadata.ValueGenerated.OnAdd;
}
}
}
}
Source:
https://stackoverflow.com/a/62380293/3850405
This can also be used to set maximum string length for all strings as an example:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
foreach (var property in modelBuilder.Model.GetEntityTypes()
.SelectMany(t => t.GetProperties())
.Where(p => p.ClrType == typeof(string)))
{
if (property.GetMaxLength() == null)
property.SetMaxLength(450);
}
}
Source:
https://stackoverflow.com/a/50852517/3850405
You can also set mark every entity that inherits from IEntity as IsTemporal:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
foreach (var et in modelBuilder.Model.GetEntityTypes())
{
if (et.ClrType.IsAssignableTo(typeof(IEntity)))
{
et.SetIsTemporal(true);
}
}
}
Source:
https://stackoverflow.com/a/75496573/3850405

Prevent index created by convention on many-to-many table

In the configuration below, EF creates an index on SyntaxId by convention. Since I have a composite primary key (serves as index) and no identity column, I do not think this convention-created index on a single column is needed in a many-to-many table.
How can I prevent this convention index (b.HasIndex("SyntaxId");) from being auto-created?
public class SoftwareSyntaxTypeConfiguration : BaseJunctionTypeConfiguration<SoftwareSyntax>
{
public override void Configure(EntityTypeBuilder<SoftwareSyntax> entityTypeBuilder)
{
base.Configure(entityTypeBuilder);
entityTypeBuilder.ToTable("software_syntaxes");
entityTypeBuilder.HasKey(x => new {x.SoftwareId, x.SyntaxId});
entityTypeBuilder.HasOne(x => x.Software)
.WithMany(x => x.SoftwareSyntaxes)
.HasForeignKey(x => x.SoftwareId);
entityTypeBuilder.HasOne(x => x.Syntax)
.WithMany(x => x.SoftwareSyntaxes)
.HasForeignKey(x => x.SyntaxId);
}
}
partial class FilterListsDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
modelBuilder.Entity("FilterLists.Data.Entities.Junctions.SoftwareSyntax", b =>
{
b.Property<int>("SoftwareId");
b.Property<int>("SyntaxId");
b.HasKey("SoftwareId", "SyntaxId");
b.HasIndex("SyntaxId"); //TODO: prevent this from being auto-created
b.ToTable("software_syntaxes");
});
}
}
Update: Adding entity classes for clarification.
public class Software
{
public int Id { get; set; }
public ICollection<SoftwareSyntax> SoftwareSyntaxes { get; set; }
...
}
public class Syntax
{
public int Id { get; set; }
public ICollection<SoftwareSyntax> SoftwareSyntaxes { get; set; }
...
}
public class SoftwareSyntax
{
public int SoftwareId { get; set; }
public Software Software { get; set; }
public int SyntaxId { get; set; }
public Syntax Syntax { get; set; }
}
As it turns out, this is not officially supported yet.
A workaround, though, is to use an internal EF API. Its use carries the caveat that it could be changed without notice as it is not intended for external use.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
((Model)modelBuilder.Model).ConventionDispatcher.StartBatch();
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
foreach (var index in entityType.GetIndexes().ToList())
// if index is one you want to remove
entityType.RemoveIndex(index.Properties);
}
via Arthur Vickers
Since I have all of my many-to-many entities in the same Junctions namespace, the implementation that works for me currently is:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
((Model)modelBuilder.Model).ConventionDispatcher.StartBatch();
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
foreach (var index in entityType.GetIndexes().ToList())
if (index.DeclaringEntityType.Name.Contains("Junctions"))
entityType.RemoveIndex(index.Properties);
}

Entity Framework Many to Many - Cannot get data

I have introduced a many to many relationship between two of my existing tables. For this, I have added a third table, which contains only the Ids of the other two tables.
Since I am using EF, I have also added
public virtual List<EntityOne> EntityOnes in EntityTwo
and
public virtual List<EntityTwo> EntityTwos in EntityOne.
However, with this, when I get the EntityTwo object, it does not contain the associated EntityOne object. The list has a count of zero, even though the data is there in the tables.
Am I missing something here? Is there anything else, I need to do?
Not sure,if this is relevant, but I have also this in OnModelCreation
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<EntityOne>().
HasMany(p => p.EntityTwos).
WithMany(a => a.EntityOnes).
Map(
m =>
{
m.MapLeftKey("EntityTwoId");
m.MapRightKey("EntityOneId");
m.ToTable("EntityRelations");
});
////Make sure a context is not created by default.
}
Try this:
public partial class One
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public virtual int Id { get; set; }
private ICollection<OneTwo> _oneTwos;
public virtual ICollection<OneTwo> OneTwos
{
get { return _oneTwos ?? (_oneTwos = new List<OneTwo>()); }
set { _oneTwos = value; }
}
}
public partial class Two
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public virtual int Id { get; set; }
private ICollection<OneTwo> _oneTwos;
public virtual ICollection<OneTwo> OneTwos
{
get { return _oneTwos ?? (_oneTwos = new List<OneTwo>()); }
set { _oneTwos = value; }
}
}
Add navigation properties to the join class:
public partial class OneTwo
{
public virtual int OneId { get; set; }
public virtual int TwoId { get; set; }
public virtual One One { get; set; }
public virtual Two Two { get; set; }
}
Add composite key to the join class and configure relationships:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<OneTwo>() // composite primary key
.HasKey(p => new { p.OneId, p.TwoId });
modelBuilder.Entity<OneTwo>()
.HasRequired(a => a.One)
.WithMany(c => c.OneTwos)
.HasForeignKey(fk => fk.OneId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<OneTwo>()
.HasRequired(a => a.Two)
.WithMany(c => c.OneTwos)
.HasForeignKey(fk => fk.TwoId)
.WillCascadeOnDelete(false);
// TODO: handle orphans when last asociation is deleted
}
An alternative strategy is to configure EF relationships via EntityTypeConfiguration<>. The following many-to-many relationship implementation demonstrates that approach:
City.cs
public partial class City
{
public virtual int Id { get; set; }
private ICollection<CountyCity> _countiesCities;
public virtual ICollection<CountyCity> CountiesCities
{
get { return _countiesCities ?? (_countiesCities = new List<CountyCity>()); }
set { _countiesCities = value; }
}
}
County.cs
public partial class County
{
public virtual int Id { get; set; }
private ICollection<CountyCity> _countiesCities;
public virtual ICollection<CountyCity> CountiesCities
{
get { return _countiesCities ?? (_countiesCities = new List<CountyCity>()); }
set { _countiesCities = value; }
}
}
CountyCity.cs
public partial class CountyCity
{
public virtual int CountyId { get; set; }
public virtual int CityId { get; set; }
public virtual County County { get; set; }
public virtual City City { get; set; }
}
CountyCityConfiguration.cs (EF 6 implementation)
public class CountyCityConfiguration : IEntityTypeConfiguration<CountyCity>
{
public void Map(EntityTypeBuilder<CountyCity> builder)
{
// Table and Schema Name declarations are optional
//ToTable("CountyCity", "dbo");
// composite primary key
builder.HasKey(p => new { p.CountyId, p.CityId });
builder.HasOne(pt => pt.County)
.WithMany(p => p.CountiesCities)
.HasForeignKey(pt => pt.CountyId)
.OnDelete(DeleteBehavior.Restrict);
builder.HasOne(pt => pt.City)
.WithMany(t => t.CountiesCities)
.HasForeignKey(pt => pt.CityId)
.OnDelete(DeleteBehavior.Restrict);
// TODO: handle orphans when last association is deleted
}
}
Entity Framework 6 Implementations:
You may configure the composite key and relationships using EntityTypeConfiguration<> as the previous code demonstrates.
Entity Framework Core Implementations:
EntityTypeConfiguration<> has not yet been migrated. However, it is on the roadmap for the next release.
In the meantime, you can employ the temporary pattern suggested by the EF team, or one of the patterns discussed this rather lengthy StackOverflow post discussing entity configuration in Entity Framework 7.
I implemented the pattern posted by Cocowalla in the lengthy discussion prior to reading the EF Team post. The source code for my workaround is available in this GitHub repository.
IEntityTypeConfiguration.cs
namespace Dna.NetCore.Core.DAL.EFCore.Configuration.Temporary.Cocowalla
{
// attribute: https://stackoverflow.com/questions/26957519/ef-7-mapping-entitytypeconfiguration/35373237#35373237
public interface IEntityTypeConfiguration<TEntityType> where TEntityType : class
{
void Map(EntityTypeBuilder<TEntityType> builder);
}
}
Here is my implementation of that pattern:
namespace Dna.NetCore.Core.DAL.EFCore.Configuration.Common
{
public class StateOrProvinceConfiguration : IEntityTypeConfiguration<StateOrProvince>
{
public void Map(EntityTypeBuilder<StateOrProvince> builder)
{
// EF Core
builder.HasOne(p => p.Country).WithMany(p => p.StateOrProvinces).HasForeignKey(s => s.CountryId).OnDelete(DeleteBehavior.Cascade);
builder.HasMany(d => d.Cities).WithOne().OnDelete(DeleteBehavior.Cascade);
builder.HasMany(d => d.Counties).WithOne().OnDelete(DeleteBehavior.Cascade);
}
}
}

Entity Framework - Lazy Loading Self Referencing Collections

Problem: I'm able to save to a self referencing collection but Entity Framework does not show them in the collection after saving to the database.
Desired: Access entities in the collection by {entity}.{collection}.{query()};
Entity:
class Feat
{
public Feat()
{
PrerequisiteFeats = new HashSet<Feat>();
}
public int Id { get; set; }
// Other properties here
public virtual ICollection<Feat> PrerequisiteFeats { get; set; }
}
Context:
class PathfinderContext : DbContext
{
public DbSet<Feat> Feats { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Feat>()
.HasMany(feat => feat.PrerequisiteFeats)
.WithMany()
.Map(m =>
{
m.MapLeftKey("FeatId");
m.MapRightKey("PrerequisiteFeatId");
m.ToTable("PrerequisiteFeats");
});
}
}
feats.Include("PrerequisiteFeats").SingleOrDefault(x => x.Id == 2)
This will basically query both Feats and Prerequisite Feats in the same query. It's combining 2 seperate queries into one.

Categories