EF Core Add-Migration generating extra column with ColumnName1 - sql-server

I have the following entities when I generate migration it creates two columns with name RestrictedCategoryId and RestrictedCategoryId1(FK). How to solve this issue to generate only one column with FK?
Note: I need OrderId in each entity.
`C#
public class Order
{
public Guid Id { get; set; }
public DateTime OrderDate { get; set; }
private List<Category> _categories;
public List<Category> Categories => _categories;
}
public class Category
{
public Guid Id { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public Guid OrderId { get; set; }
public Order Order { get; set; }
private List<RestrictionCategory> _restrictedCategories;
public List<RestrictionCategory> RestrictedCategories => _restrictedCategories;
}
public class RestrictionCategory
{
public Guid Id { get; set; }
public string Name { get; set; }
public Guid OrderId { get; set; }
public Order Order { get; set; }
public Guid CategoryId { get; set; }
public Category Category { get; set; }
public Guid RestrictedCategoryId { get; set; }
public Category RestrictedCategory { get; set; }
}
public class OrderConfiguration : IEntityTypeConfiguration<Order>
{
public void Configure(EntityTypeBuilder<Order> builder)
{
builder.HasKey(o => o.Id);
builder.Property(o => o.Id).IsRequired();
}
}
public class CategoryConfiguration : IEntityTypeConfiguration<Category>
{
public void Configure(EntityTypeBuilder<Category> builder)
{
builder.HasKey(c => new { c.Id, c.OrderId });
builder.Property(o => o.Id).IsRequired();
builder.Property(o => o.OrderId).IsRequired();
builder.HasMany(c => c.RestrictedCategories).WithOne(cr => cr.Category)
.HasForeignKey(cr => new { cr.CategoryId, cr.OrderId
}).OnDelete(DeleteBehavior.NoAction);
}
}
public class RestrictionCategoryConfiguration : IEntityTypeConfiguration<RestrictionCategory>
{
public void Configure(EntityTypeBuilder<RestrictionCategory> builder)
{
builder.HasKey(c => new { c.Id, c.OrderId });
builder.Property(o => o.Id).IsRequired();
builder.Property(o => o.OrderId).IsRequired();
builder.HasIndex(cr => new { cr.RestrictedCategoryId, cr.OrderId });
}
}
`
The entities resembles to actual ones.

Actually you get two additional columns:
RestrictedCategoryId = table.Column<Guid>(nullable: false),
RestrictedCategoryId1 = table.Column<Guid>(nullable: true), // <--
RestrictedCategoryOrderId = table.Column<Guid>(nullable: true) // <--
Apparently EF Core Foreign Key Conventions doesn't play well with composite keys, so you have to explicitly configure the relationship - similar to what you did for the other relationship, just since your model has no corresponding collection navigation property you have to use HasMany with generic type argument and no parameters, e.g. inside CategoryConfiguration:
builder.HasMany<RestrictionCategory>()
.WithOne(cr => cr.RestrictedCategory)
.HasForeignKey(cr => new { cr.RestrictedCategoryId, cr.OrderId})
.OnDelete(DeleteBehavior.NoAction);

Related

Migration conflicts in net core Entity Framework

I have two tables in my SQL Server database - one for categories:
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public int? ParentId { get; set; }
[ForeignKey("ParentId")]
public Category Parent { get; set; }
}
And then the Assistant table:
public class Assistant
{
public int Id { get; set; }
public int UserId { get; set; }
public DateTime CreatedAtUtc { get; set; }
public Status Status { get; set; }
public int? CategoryId { get; set; }
[ForeignKey("CategoryId")]
public Category Category { get; set; }
}
When I try to make a migration I get this error:
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_Assistants_Categories_CategoryId". The conflict occurred in database "Pirma
isMsSql", table "dbo.Categories", column 'Id'.
I have no idea why.
Thanks
Fix your classes:
public partial class Assistent
{
[Key]
public int Id { get; set; }
public int UserId { get; set; }
public User User{ get; set; }
public DateTime CreatedAtUtc { get; set; }
public int StatusId { get; set; }
public Status Status { get; set; }
public int? CategoryId { get; set; }
[ForeignKey(nameof(CategoryId))]
[InverseProperty("Assistents")]
public virtual Category Category { get; set; }
}
public partial class Category
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int? ParentId { get; set; }
[ForeignKey(nameof(ParentId))]
[InverseProperty(nameof(Category.InverseParent))]
public virtual Category Parent { get; set; }
[InverseProperty(nameof(Assistent.Category))]
public virtual ICollection<Assistent> Assistents { get; set; }
[InverseProperty(nameof(Category.Parent))]
public virtual ICollection<Category> InverseParent { get; set; }
}
This is db context:
public partial class AssistentsContext : DbContext
{
public AssistentsContext()
{
}
public AssistentsContext(DbContextOptions<AssistentsContext> options)
: base(options)
{
}
public virtual DbSet<Assistent> Assistents { get; set; }
public virtual DbSet<Category> Categories { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Assistent>(entity =>
{
entity.HasOne(d => d.Category)
.WithMany(p => p.Assistents)
.HasForeignKey(d => d.CategoryId);
});
modelBuilder.Entity<Category>(entity =>
{
entity.HasOne(d => d.Parent)
.WithMany(p => p.InverseParent)
.HasForeignKey(d => d.ParentId);
});
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}

How to get all data from ef core many to many

On EF core have Two tables(Page, Group) both have many to many relations with junction table GroupPage. Want to get all pages data with junction table related data based on groupId as like bellow.
If you construct your EF relation correctly you should not have a GroupPage entity.
See Entity Framework Database First many-to-many on how to construct your EF EDM correctly.
Once you have your EDM correctly mapped, you should have the classes
public class Page
{
public int Id { get; set; }
public ICollection<Group> Groups { get; set; }
...
}
public class Group
{
public int Id { get; set; }
public ICollection<Page> Pages { get; set; }
...
}
Then you just need to do the following
public IQueryable<Page> GetPages(int groupId)
{
return from group in _context.Groups
where group.Id == groupId
from page in group.Pages
select page;
}
The following syntax is self-descriptive. Here are the entities structure and Page Dto.
public class Page
{
public int Id { get; set; }
public ICollection<Group> Groups { get; set; }
...
}
public class Group
{
public int Id { get; set; }
public ICollection<Page> Pages { get; set; }
...
}
public class PageGroup
{
public int PageId { get; set; }
public Page Page { get; set; }
public int GroupId { get; set; }
public Group Group { get; set; }
}
public class PagesDto
{
public string Name { get; set; }
public int GroupId { get; set; }
public int PageId { get; set; }
public string Description { get; set; }
public string Tab { get; set; }
public string Module { get; set; }
public bool? IsActive { get; set; }
public bool? IsDefault { get; set; }
public PagesDto()
{
IsActive = false;
IsDefault = false;
}
}
Following function help us to get group related pages information.
public async Task<List<PagesDto>> GetAllPagesByGroupId(int selectedGroupId)
{
//get all pages
var pages = await _pagesRepository.GetAll().Select(p => new PagesDto {
PageId = p.Id,
Name = p.Name,
GroupId = 0
}).ToListAsync();
//get group ralated pages
var selectedGroupPageIds = _groupPagesRepository
.GetAll()
.Where(p => p.GroupId == selectedGroupId)
.Select(p => p.PageId);
//update page information base on group related pages info.
foreach (var item in pages.Where(p=>selectedGroupPageIds.Contains(p.PageId)))
{
item.GroupId = selectedGroupId;
}
return pages;
}

How do I model a 'has a' database relationship with multiple principles?

In code I have an object graph that looks like this:
public class Author
{
public int AuthorId { get; set; }
public string Name { get; set; }
public Address Address { get; set; }
}
public class Publisher
{
public int PublisherId { get; set; }
public string Name { get; set; }
public Address Address { get; set; }
}
public class Address
{
public int AddressId { get; set; }
public string Postcode { get; set; }
}
How do I model this in a relational database schema?
This needs to be a 0-1..1 relation, i.e. Authors and Publishers may either have or not have an Address.
Ideally Addresses would have to be referenced by either an Author or a Publisher but not both.
Massive bonus respect if you can model it in Entity Framework Core using navigation properties and have cascade delete remove the Address when an Author or Publisher is removed. (But I'm betting no one will be able to).
I'd list all the things I've tried, but the post would be so long no one would read it. It'll be quicker just to say I've tried everything I can think of.
There are many ways you can achieve the goal in EF Core. The key point is that Address will be the dependent end of the relationships and it will contain optional FKs to the principal entities Author and Publisher.
Here are the possible Address models and configurations:
(1) Address with explicit FK and navigation properties
Model:
public class Address
{
public int AddressId { get; set; }
public string Postcode { get; set; }
public int? AuthorId { get; set; }
public Author Author { get; set; }
public int? PublisherId { get; set; }
public Publisher Publisher { get; set; }
}
Configuration:
modelBuilder.Entity<Author>()
.HasOne(e => e.Address)
.WithOne(e => e.Author)
.HasForeignKey<Address>(e => e.AuthorId)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Publisher>()
.HasOne(e => e.Address)
.WithOne(e => e.Publisher)
.HasForeignKey<Address>(e => e.PublisherId)
.OnDelete(DeleteBehavior.Cascade);
(2) Address with navigation properties only
Model:
public class Address
{
public int AddressId { get; set; }
public string Postcode { get; set; }
public Author Author { get; set; }
public Publisher Publisher { get; set; }
}
Configuration:
modelBuilder.Entity<Author>()
.HasOne(e => e.Address)
.WithOne(e => e.Author)
.HasForeignKey<Address>("AuthorId")
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Publisher>()
.HasOne(e => e.Address)
.WithOne(e => e.Publisher)
.HasForeignKey<Address>("PublisherId")
.OnDelete(DeleteBehavior.Cascade);
(3) Address with explicit FK properties only
Model:
public class Address
{
public int AddressId { get; set; }
public string Postcode { get; set; }
public int? AuthorId { get; set; }
public int? PublisherId { get; set; }
}
Configuration:
modelBuilder.Entity<Author>()
.HasOne(e => e.Address)
.WithOne()
.HasForeignKey<Address>(e => e.AuthorId)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Publisher>()
.HasOne(e => e.Address)
.WithOne()
.HasForeignKey<Address>(e => e.PublisherId)
.OnDelete(DeleteBehavior.Cascade);
(4) Address without explicit FK and navigation properties
Model:
public class Address
{
public int AddressId { get; set; }
public string Postcode { get; set; }
}
Configuration:
modelBuilder.Entity<Author>()
.HasOne(e => e.Address)
.WithOne()
.HasForeignKey<Address>("AuthorId")
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Publisher>()
.HasOne(e => e.Address)
.WithOne()
.HasForeignKey<Address>("PublisherId")
.OnDelete(DeleteBehavior.Cascade);
Reference: Relationships

Entity Framework Model Mapping With Legacy Database and Constant

I'm using EF6 over a DB that's over 15 years old. I did not make this architecture decision. All of my experience with EF has been code-first, with models I've created myself.
One of our tables has a reference table that has some info needed in selects only. These mappings will never be used for update/insert/delete.
I have two entities. My primary table:
public class QualParam
{
[Key]
public string MillId { get; set; }
[Key]
public string Qparam { get; set; }
public string ValueNum { get; set; }
public string ActiveFlag { get; set; }
public int ModifiedTimestamp { get; set; }
public int CreatedTimestamp { get; set; }
public decimal SbIncrement { get; set; }
public string QualityDesc { get; set; }
public string TypeCode { get; set; }
public QualParamHeader QualParamHeader { get; set; }
public virtual UnitMeasure UnitMeasure { get; set; }
}
and a reference table:
public class UnitMeasure
{
[Key]
public string UnitOfMeasure { get; set; }
public int ModifiedTimestamp { get; set; }
public int CreatedTimestamp { get; set; }
public string BaseUnits { get; set; }
public string UnitDesc { get; set; }
[Key]
public string TableName { get; set; }
public string RollWeightFlag { get; set; }
public string MetricFlag { get; set; }
public string MxActionCode { get; set; }
[Key]
public string TypeCode { get; set; }
public byte[] RecordVersion { get; set; }
public List<QualParam> QualParams { get; set; }
}
QualParam may have a UnitMeasure, and UnitMeasure can have many QualParams, easy, right?
In SQL the join is done thusly
SELECT *
FROM qual_params AS q
LEFT JOIN unit_measure AS u
ON u.unit_meas = q.unit_meas
AND u.table_name = 'qual_params'
AND u.type_code = q.type_code
So yes, there's a constant, the table name, and yes the keys from the source to the reference tables don't match, and aren't even enumerated in the db to begin with. Again, legacy.
Our Db context-
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new QualParamsConfiguration());
modelBuilder.Configurations.Add(new UnitMeasureConfiguration());
base.OnModelCreating(modelBuilder);
}
I'm using auto generated configs-
public QualParamConfiguration()
: this("dbo")
{
}
public QualParamConfiguration(string schema)
{
ToTable(schema + ".qual_params");
HasKey(x => new { x.MillId, x.Qparam });
Property(x => x.Qparam).HasColumnName(#"qparam").IsRequired().IsFixedLength().IsUnicode(false).HasColumnType("char").HasMaxLength(10).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None);
Property(x => x.ValueNum).HasColumnName(#"value_num").IsRequired().IsFixedLength().IsUnicode(false).HasColumnType("char").HasMaxLength(9);
Property(x => x.ActiveFlag).HasColumnName(#"active_flag").IsRequired().IsFixedLength().IsUnicode(false).HasColumnType("char").HasMaxLength(1);
Property(x => x.ModifiedTimestamp).HasColumnName(#"ts_modified").IsRequired().HasColumnType("int");
Property(x => x.CreatedTimestamp).HasColumnName(#"ts_create").IsRequired().HasColumnType("int");
Property(x => x.SbIncrement).HasColumnName(#"sb_increment").IsRequired().HasColumnType("decimal").HasPrecision(7, 3);
Property(x => x.QualityDesc).HasColumnName(#"quality_desc").IsRequired().IsFixedLength().IsUnicode(false).HasColumnType("char").HasMaxLength(50);
Property(x => x.MillId).HasColumnName(#"mill_id").IsRequired().IsFixedLength().IsUnicode(false).HasColumnType("char").HasMaxLength(10).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None);
this.HasRequired(a => a.QparamHeader).WithMany(b => b.QualParams).HasForeignKey(c => c.Qparam).WillCascadeOnDelete(false);
}
The last navigation wrote itself, for obvious reasons. Simple relationship.
This one, not so much. I'm open to everything- I'm fairly aware at this point that I'll have to create a separate model to achieve this.
The examples I've seen using .Map must be from older versions of EF, since many of the methods are not available to me. Is it even possible to achieve this relationship?

How to access foreign key values on MVC view?

I'm having trouble accessing foreign key values in my view without using a partial.
I have tblProperty as Primary_Key and tblCustomer as foreign_key. I want to access the values of my foreign keys in my view but can't figure out why.
Model
public partial class tblProperty
{
public tblProperty()
{
this.Images = new HashSet<Image>();
this.tblCustomers = new HashSet<tblCustomer>();
}
public int propertyID { get; set; }
public string address { get; set; }
public string description { get; set; }
public virtual ICollection<Image> Images { get; set; }
public virtual ICollection<tblCustomer> tblCustomers { get; set; }
}
public partial class tblCustomer
{
public int customerID { get; set; }
public string name { get; set; }
public decimal contactNumber { get; set; }
public string notes { get; set; }
public Nullable<int> propertyID { get; set; }
public virtual tblProperty tblProperty { get; set; }
}
controller
public class propertyController : Controller
{
propertyDBEntities2 dc = new propertyDBEntities2();
public ActionResult List()
{
var properties = dc.tblProperties.Include(p => p.tblCustomers);
return View(properties.ToList());
}
public ActionResult Details(int id = 0)
{
var properties = dc.tblProperties.Include(p => p.tblCustomers);
tblProperty property = dc.tblProperties.Find(id);
tblCustomer customer = dc.tblCustomers.Find(id);
if (properties == null)
{
return HttpNotFound();
}
return View(dc.tblProperties.Find(id));
}
public ActionResult Create()
{
return View();
}
[HttpPost, ValidateAntiForgeryToken]
public ActionResult Create(tblProperty e)
{
if (ModelState.IsValid)
{
using (dc)
{
dc.tblProperties.Add(e);
dc.SaveChanges();
}
}
return RedirectToAction("List");
}
view
(like model.name is trying to access name from tblCustomer)
#model myProject.tblProperty
#Html.DisplayFor(model => model.name)
tblProperty doesnt have name.
I guess you need
#Html.DisplayFor(model => model.tblCustomer.name)
But just debug it or use intellisense
EDIT:
In my project I create a dtoClass Data Transfer Object
So for my avl class I have a dtoAvl
avl Class:
public partial class avl
{
public avl()
{
this.cars = new HashSet<cars>();
}
public long avl_id { get; set; }
public Nullable<long> car_id { get; set; }
public Nullable<decimal> speed { get; set; }
// this class contain info regarding the road
public virtual manila_rto manila_rto { get; set; }
public virtual ICollection<cars> cars { get; set; }
}
I create a dtoAvl
public class dtoAvl
{
public long Avl_ID { get; set; }
public long? Car_ID { get; set; }
public string RoadName { get; set; } // came from manila_rto
public int Speed { get; set; }
}
My controler
List<dtoAvl> result = db.avls.Select(
r => new dtoAvl
{
Avl_ID = r.Avl_ID,
Car_ID = r.Car_ID,
Speed = r.Speed,
// here is a propery but can be a list
RoadName = r.manila_rto.name
}).ToList();
return PartialView(result);
View:
#model IEnumerable<dtoAvl>

Resources