CTP5: self-reference issue? - entity-framework-ctp5

there is a simple model:
public class Node
{
public long Id { get; set; }
public virtual Node Parent { get; set; }
}
the following map code will throw an exception:
public class NodeContext : DbContext
{
public DbSet<Node> Nodes { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Node>().HasOptional(n => n.Parent).WithMany().IsIndependent().Map(m => m.MapKey(p => p.Id, "ParentId"));
}
}
Could it be that it is not capable of self-reference custom foreign key name do it?

I do the same, but I don't rely on EF getting the keys correct and I do it myself. So my Node class looks like the following:
public class Node
{
public int Id {get;set;}
public int ParentId {get;set;}
public virutal Node Parent {get;set;}
public virtual ICollection<Node> Children {get;set;}
}
And then the ModelBuilder is setup as follows:
builder.Entity<Node>().HasKey(x => x.Id);
builder.Entity<Node>()
.HasOptional(s => s.Parent)
.WithMany(c => c.Children)
.HasForeignKey(s => s.ParentId);
builder.Entity<Node>().ToTable("Node");

Related

No suitable constructor for entity type 'LineString'

Trying to migrate integration tests from the in-memory database to the PostGIS one, I always catch that exception when I call EnsureDeleted or EnsureCreated methods:
System.InvalidOperationException
No suitable constructor found for entity type 'LineString'. The following constructors had parameters that could not be bound to properties of the entity type: cannot bind 'points' in 'LineString(Coordinate[] points)'; cannot bind 'points', 'factory' in 'LineString(CoordinateSequence points, GeometryFactory factory)'.
With in-memory tests, all is working fine.
The only model with spatial data is this:
public class SurveilledArea
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
[Column(TypeName = "geometry (polygon)")]
public Polygon Polygon { get; set; }
public string AvigilonAlertId { get; set; }
public int MunicipalityId { get; set; }
public virtual Municipality Municipality { get; set; }
}
and my DbContext is this
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> dbContextOptions) : base(dbContextOptions)
{
}
public virtual DbSet<SurveilledArea> Areas { get; set; }
public virtual DbSet<Municipality> Municipalities { get; set; }
public virtual DbSet<Report> Reports { get; set; }
public virtual DbSet<Device> Devices { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasPostgresExtension("postgis");
modelBuilder.Entity<SurveilledArea>()
.HasOne(p => p.Municipality)
.WithMany(p => p.SurveilledAreas)
.HasForeignKey(p => p.MunicipalityId)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Report>()
.HasOne(p => p.Device)
.WithMany(p => p.Reports)
.HasForeignKey(p => new { p.DeviceType, p.DeviceAdId })
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Municipality>()
.HasIndex(p => p.ShortCode)
.IsUnique();
modelBuilder.Entity<Device>()
.HasKey(device => new {device.Type, device.AdvertisingId});
base.OnModelCreating(modelBuilder);
}
}
What am I doing wrong?
I had a similar problem with a class that contained a Polygon property
public NetTopologySuite.Geometries.Polygon Polygon { get; set; }
You may need to add a package ref to Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite
Then in your data context builder implement something like this
public static MyDataContext CreateContext(string sqlConnectionStr) {
var optionsBuilder = new DbContextOptionsBuilder<MyDataContext>();
optionsBuilder.UseSqlServer(sqlConnectionStr, x => x.UseNetTopologySuite()
return new MyDataContext(optionsBuilder.Options);
}

EF Core Entity Circular Reference

I am using C#.net and ef core. I have the models below. When I get my list of competitions, I want to only get my related user. However, I am getting the User and all the User's competitions. How can I achieve this? I had to do the following to get my list of competitions to show:
.AddJsonOptions(opt => opt.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore)
public partial class Competition
{
public int CompetitionId { get; set; }
public int UserId { get; set; }
public User User { get; set; }
}
public partial class User
{
public int UserId { get; set; }
public string Email { get; set; }
public string UserName { get; set; }
public ICollection<Competition> Competitions { get; set; }
}
I have an api that uses entity framework to make calls to my database using the models describe above. The call in my api that causes the circular reference is the following:
[Produces("application/json")]
[Route("api/Competitions")]
public class CompetitionsController : Controller
{
private readonly ApplicationDBContext _context;
public CompetitionsController(ApplicationDBContext context)
{
_context = context;
}
// GET: api/Competitions
[HttpGet]
public IEnumerable<Competition> GetCompetitions()
{
//return _context.Competitions;
return _context.Competitions
.Include(u => u.User).ToList();
}
}
Below is my onmodelcreating code block in my ApplicationDBContext class:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Competition>(entity =>
{
entity.HasKey(e => e.CompetitionId);
entity.HasOne(d => d.User)
.WithMany(p => p.Competitions)
.HasForeignKey(d => d.UserId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_Competitions_Users");
});
modelBuilder.Entity<User>(entity =>
{
entity.HasKey(e => e.UserId);
entity.HasIndex(e => e.UserName)
.HasName("UC_UserName")
.IsUnique();
entity.Property(e => e.Email)
.HasMaxLength(40)
.IsUnicode(false);
entity.Property(e => e.UserName)
.HasMaxLength(40)
.IsUnicode(false);
});
}
Old question, but in case someone still looking.
One solution is:
services.AddMvc()
.AddJsonOptions(options => {
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});
You should have ignored Competitions collection in user model while building.
modelBuilder.Entity<User>()
.Ignore(b => b.Competitions);

EF table splitting with table AspNetUsers

I use two classes.
public partial class User
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public ICollection<IntRole> Roles { get; set; }
public virtual ApplicationUser ApplicationUser { get; set; }
}
public partial class ApplicationUser : IdentityUser<int, IntUserLogin, IntUserRole, IntUserClaim>
{
public virtual User User { get; set; }
}
I want to map both classes to table AspNetUsers.
I configured all fields in this table to make them optional.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<ApplicationUser>().HasOptional(a => a.User).WithMany().HasForeignKey(a => a.Id);
modelBuilder.Entity<ApplicationUser>().HasRequired(a => a.User).WithRequiredDependent(s => s.ApplicationUser);
modelBuilder.Entity<ApplicationUser>().Property(a => a.EmailConfirmed).IsOptional();
modelBuilder.Entity<ApplicationUser>().Property(a => a.PhoneNumber).IsOptional();
modelBuilder.Entity<ApplicationUser>().Property(a => a.PhoneNumberConfirmed).IsOptional();
modelBuilder.Entity<ApplicationUser>().Property(a => a.TwoFactorEnabled).IsOptional();
modelBuilder.Entity<ApplicationUser>().Property(a => a.LockoutEnabled).IsOptional();
modelBuilder.Entity<ApplicationUser>().Property(a => a.AccessFailedCount).IsOptional();
modelBuilder.Entity<ApplicationUser>().Property(a => a.UserName).IsOptional();
modelBuilder.Entity<User>().ToTable("AspNetUsers");
}
I make automatic migration and the result is successful.
When I want to add single User defined by class User in controller.
context.SpecialUser.Add(new Models.User { FirstName = "Halo", LastName = "Halo2" });
context.SaveChanges();
I got the following info.
Invalid data encountered. A required relationship is missing. Examine StateEntries to determine the source of the constraint violation.
What relationship should I define?
Result of InnerException.

model builder add one column more?

I use EF code first.
It's my modelbuilder
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<Market>()
.HasRequired(s => s.State)
.WithMany()
.HasForeignKey(s => s.StateId)
.WillCascadeOnDelete(false);
}
and State Class :
public class State
{
public State()
{
Markets = new HashSet<Market>();
}
[Key]
public int StateId { get; set; }
public string StateName { get; set; }
// navigation property
public virtual ICollection<Market> Markets { get; set; }
}
and Market class :
public class Market
{
[Key]
public int MarketId { get; set; }
public string MarketName { get; set; }
public int StateId { get; set; }
// navigation property
public virtual State State { get; set; }
}
Of course I remove extra code.
Problem is when I use this code , an State_StateId column add to my Market table in database, and when I do not use modelbuilder an error occurred with message loop code and ... (I say that I remove extra code), so how can I use code first without this "State_StateId" extra column.
excuse me for bad english writing.
If you want to remove State_StateId column set the configuration completely like the code below and don't let WithMany empty:
modelBuilder.Entity<Market>()
.HasRequired(s => s.State)
.WithMany(p => p.Markets)
.HasForeignKey(s => s.StateId)
.WillCascadeOnDelete(false);
Or you can just remove the Fluent API configuration and let EF use the default configuration convention and will set all tables, primary keys, foreign keys and column name for you.

EntityFramework Code-First: How to prevent cascade delete on one side of a many-to-many relationship?

Is it possible to prevent cascade delete from a single way with Entity Framework Code-First.
Here is a sample code:
public sealed class ZeContext : DbContext
{
static ZeContext()
{
Database.SetInitializer(new CreateDatabase());
}
public IDbSet<A> As { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<A>()
.ToTable("A")
.HasMany<B>(a => a.Bs)
.WithMany(b => b.As)
;
modelBuilder.Entity<B>()
.ToTable("B")
.HasMany<A>(b => b.As)
.WithMany(a => a.Bs)
;
base.OnModelCreating(modelBuilder);
}
}
public class A
{
public Guid Id { get; set; }
public virtual ICollection<B> Bs { get; set; }
}
public class B
{
public Guid Id { get; set; }
public virtual ICollection<A> As { get; set; }
}
I would like to configure the following behaviour:
When deleting a record from table A, it should remove the corresponding association records from the internal many-to-many table created by EntityFramework.
However, when deleting a record from table B, it should fail if there is a corresponding association record in the internal many-to-many table.

Resources