EF6 many to many duplicate column - entity-framework

I got a database first many to many between
UsagerEW <> PermissionsUsagerEW <> Permissions
I manually add the Many2Many relation:
modelBuilder.Entity<PermissionUsagerEW>().HasKey(k => k.id);
modelBuilder.Entity<UsagerEW>()
.HasMany(u => u.Permissions)
.WithMany(p => p.UsagerEWs)
.UsingEntity<PermissionUsagerEW>(
p => p.HasOne(e => e.permission)
.WithMany()
.HasForeignKey(e => e.permissionId),
p => p.HasOne(p => p.usagerEWcode_intNavigation)
.WithMany()
.HasForeignKey(e => e.usagerEWcode_int)
);
The midle table EF generate:
public partial class PermissionUsagerEW
{
public int id { get; set; }
public int permissionId { get; set; }
public int usagerEWcode_int { get; set; }
public virtual Permission permission { get; set; }
public virtual UsagerEW usagerEWcode_intNavigation { get; set; }
}
It’s an old database and some table do not have an id as FK and got code_int instead.
Everything works well except when I try to add permission to one user.
I try updating directly the PermissionsUsagerEW (middle table) or by the navigation properties of the user table.
In each case I got this error:
The column name 'permissionId' is specified more than once in the SET clause or column list of an INSERT.
When I look in the generated SQL code, I see that the 2 fields are duplicate with the same name but starting with a capital letter:
SET NOCOUNT ON;
INSERT INTO [PermissionUsagerEW] ([Permissionid], [UsagerEWcode_int], [permissionId], [usagerEWcode_int])
VALUES (#p0, #p1, #p2, #p3);
SELECT [id]
FROM [PermissionUsagerEW]
WHERE ##ROWCOUNT = 1 AND [id] = scope_identity();
Any idea?

Related

EF Core 5 many to many relationship to the same table?

A product can have many other related products. The following creates the join table perfectly but when I add a product to another product's RelatedProducts I get the following error on save: 'The value of 'ProductAssociation.ProductID' is unknown when attempting to save changes. This is because the property is also part of a foreign key for which the principal entity in the relationship is not known.'
modelBuilder.Entity<Product>()
.HasMany(x => x.RelatedProducts)
.WithMany(r => r.RelatedProducts)
.UsingEntity<ProductAssociation>(
x => x.HasOne(p => p.RelatedProduct).WithMany().HasForeignKey(f => f.RelatedProductID),
x => x.HasOne(p => p.Product).WithMany().HasForeignKey(f => f.ProductID).OnDelete(DeleteBehavior.NoAction),
x => x.ToTable("ProductAssociations"));
I think this is a similar answer
Entity Framework Core 2.0 many-to-many relationships same table
I also solved it with that provide link above like this in core 3+.
Product table
public class Product
{
// Other properties members ....
public ICollection<Product> Products { get; set; }
public ICollection<Product> ProductOf { get; set; }
}
Product Association table "ProductSet"
public class ProductSet
{
public int ProductId { get; set; }
public int SubProductId { get; set; }
}
OnModelCreating()
modelBuilder.Entity<Product>()
.HasMany(e => e.Products)
.WithMany(e => e.ProductOf)
.UsingEntity<ProductSet>(
e => e.HasOne<Product>().WithMany().HasForeignKey(e => e.ProductId),
e => e.HasOne<Product>().WithMany().HasForeignKey(e => e.SubProductId));

Correct way to save an object containint a one on one relationship with another object

I have an object that is containing another object, when the DB is empty it saves perfectly, but once there are objects in the DB, i get an entity error
i tried filling the fields up manually before i called the savechanges. inspected the object and the values are inside, but then the exception is happening and it seems the objects are emtpy in the EntityValidationErrors
public class Address
{
public int Id { get; set; }
[Display(Name = "Address Line 1")]
public string AddressLine1 { get; set; }
[Display(Name = "Address Line 2")]
public string AddressLine2 { get; set; }
public string Postcode { get; set; }
public string City { get; set; }
public string Country { get; set; }
}
public class Invoice
{
public int Id { get; set; }
public Address Address1 { get; set; }
public Address Address2 { get; set; }
}
The configuration for Address
HasKey(m => m.Id);
Property(m => m.AddressLine1).IsRequired();
Property(m => m.Postcode).IsRequired();
Property(m => m.City).IsRequired();
Property(m => m.Country).IsRequired();
When i want to save the Invoice i get a conflict that the Address values should contain a value like AddressLine1, Postcode, City and Country.
But i am 100% sure it does contain a value before i call the SaveChanges() method
i didn't expect to have an exception. since when the db is empty, it is working perfectly.
I can see a number of possible errors.
Firstly, are you counting on the database to generate Ids with Identity columns? If so, you need to notify EF of this fact:
HasKey(x => x.Id)
.Property(x => x.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Same goes for the Invoice Id configuration. Otherwise your database will insert the first record with ID = 0, and follow up inserts would lead to duplicate PKs.
Secondly, you need to map the FK from Invoice to the two Address records. I'll assume that the Invoice table will have Address1Id and Address2Id to point to the two addresses:
In the invoice configuration:
HasOptional(x => x.Address1)
.WithMany()
.Map(x => x.MapKey("Address1Id");
HasOptional(x => x.Address2)
.WithMany()
.Map(x => x.MapKey("Address2Id");
This assumes EF6 where your Invoice Entity does not expose properties for the two FKs. (preferrable) If you do expose the FK properties then replace the .Map(...) calls with .HasForeignKey(x => x.Address1Id). If this is EF Core you replace .Map(...) with .HasForeignKey("Address1Id") to create a shadow property for the mapping.
If you're still having issues, update your question to include:
The complete class and configuration for the two entities. (Invoice and Address)
The exact error message that you are getting
... and we can take it from there.

EF Core Unable to determine the relationship represented by navigation property 'Colour.ColourGroups' of type 'ICollection<ColourGroup>'

I have the following 3 tables in a legacy database.
CREATE TABLE Colour(
ColourCode char(3) NOT NULL,
CONSTRAINT PK_Colour PRIMARY KEY CLUSTERED
(
ColourCode ASC
)
CREATE TABLE ColourGroup(
ColourGroup varchar(6) NOT NULL,
CONSTRAINT PK_ColourGroup PRIMARY KEY CLUSTERED
(
ColourGroup ASC
)
CREATE TABLE Colour_ColourGroup(
ColourCode char(3) NOT NULL,
ColourGroup varchar(6) NOT NULL,
CONSTRAINT PK_Colour_ColourGroup PRIMARY KEY CLUSTERED
(
ColourCode ASC,
ColourGroup ASC
)
ALTER TABLE Colour_ColourGroup WITH CHECK ADD CONSTRAINT FK_Colour_ColourGroup_Colour FOREIGN KEY(ColourCode)
REFERENCES Colour (ColourCode)
ALTER TABLE Colour_ColourGroup WITH CHECK ADD CONSTRAINT FK_Colour_ColourGroup_ColourGroup FOREIGN KEY(ColourGroup)
REFERENCES ColourGroup (ColourGroup)
and the following EF classes to represent them in code
public class Colour
{
public string ColourId { get; set; }
public ICollection<ColourGroup> ColourGroups { get; set; }
}
public class ColourGroup
{
public string ColourGroupId { get; set; }
public ICollection<Colour> Colours { get; set; }
}
public class ColourColourGroup
{
public string ColourId { get; set; }
public string ColourGroupId { get; set; }
public Colour Colour { get; set; }
public ColourGroup ColourGroup { get; set; }
}
I'm using Fluent API to link ColourColourGroup to the Colour_ColourGroup table and to specify some DB column names.
builder.Entity<Colour>(entity =>
{
entity.Property(e => e.ColourId).HasColumnType("char(3)")
.HasColumnName("ColourCode");
entity.Property(e => e.FinishId).HasMaxLength(3);
entity.Property(e => e.Description).HasMaxLength(30);
entity.HasKey(e => e.ColourId);
});
builder.Entity<ColourGroup>(entity =>
{
entity.Property(e => e.ColourGroupId).HasMaxLength(6)
.HasColumnName("ColourGroup");
entity.HasKey(e => e.ColourGroupId);
});
builder.Entity<ColourColourGroup>(entity =>
{
entity.ToTable("Colour_ColourGroup");
entity.Property(e => e.ColourGroupId).HasMaxLength(6)
.HasColumnName("ColourGroup");
entity.Property(e => e.ColourId).HasMaxLength(3)
.HasColumnName("ColourCode");
entity.HasKey(e => new { e.ColourId, e.ColourGroupId });
});
But I don't know how to link the 3 tables together. If it was just a one-to-many relationship between Colour and ColourGroup, I think you'd use InverseProperty (or whatever the Fluent equivalent is) on ColourGroup.Colours.
Any query that accesses these entities fail with the above error, for example:
var group = _context.ColourGroups.Where(g => g.ColourGroupId == "ALLPC").FirstOrDefault();
How do I tell EF that the Colour.ColourGroups and ColourGroup.Colours properties are "mapped" by the corresponding properties in ColourColourGroup?

Entity Framework - One-way one-to-one relation

I need to make a one-to-one relation between two tables, but only one-way.
[Accounts]
account_id
name
etc...
[SalesReps]
sales_rep_id
account_id
account
etc...
So, I want the SalesReps table to have a relation to Accounts, but I don't want Accounts to have a reference to SalesReps.
I tried this:
modelBuilder.Entity<sales_rep>()
.HasRequired(a => a.account)
.WithMany()
.HasForeignKey(a => a.account_id);
But that gives me:
sales_rep_account_Source: : Multiplicity is not valid in Role 'sales_rep_account_Source' in relationship 'sales_rep_account'. Because the Dependent Role refers to the key properties, the upper bound of the multiplicity of the Dependent Role must be '1'.
The way you do this is with WithRequiredDependent() configuration. Your entities will be:
public class Account
{
public int Id { get; set; }
public string Name { get; set; }
}
public class SalesRep
{
public int Id { get; set; }
public Account Account { get; set; }
}
In OnModelCreating() method you should do this:
modelBuilder.Entity<Account>().HasKey(x => x.Id);
modelBuilder.Entity<SalesRep>().HasKey(x => x.Id);
modelBuilder.Entity<SalesRep>().HasRequired(x => x.Account).WithRequiredDependent().Map(x => x.MapKey("AccountId"));
It turns out, that all I had to do was:
modelBuilder.Entity<sales_rep>()
.HasRequired(a => a.account)
.WithOptional();

Invalid column name in EF

I have a situation where EF is trying to get a field value from the table "VideoClip" that I didn't ask it to get.
The complete generated query looks like this:
SELECT
[Project1].[Id] AS [Id],
[Project1].[NewsItemId] AS [NewsItemId],
[Project1].[VideoClipId] AS [VideoClipId],
[Project1].[DisplayOrder] AS [DisplayOrder],
[Project1].[Video_Id] AS [Video_Id]
FROM ( SELECT
[Extent1].[Id] AS [Id],
[Extent1].[NewsItemId] AS [NewsItemId],
[Extent1].[VideoClipId] AS [VideoClipId],
[Extent1].[DisplayOrder] AS [DisplayOrder],
[Extent1].[Video_Id] AS [Video_Id]
FROM [dbo].[NewsItemVideoClip] AS [Extent1]
WHERE [Extent1].[NewsItemId] = #p__linq__0
) AS [Project1]
ORDER BY [Project1].[DisplayOrder] DESC
However, my NewsItemVideoClip entity class looks like this:
public class NewsItemVideoClip : Entity
{
public virtual int NewsItemId { get; set; }
public virtual int VideoClipId { get; set; }
public virtual int DisplayOrder { get; set; }
public virtual NewsItem NewsItem { get; set; }
public virtual VideoClip VideoClip { get; set; }
}
The mapping:
public class NewsItemVideoClipEntityMapping
: EntityTypeConfiguration<NewsItemVideoClip>
{
public NewsItemVideoClipEntityMapping()
{
//configure key and properties
HasKey(c => c.Id);
this.HasRequired(x => x.NewsItem)
.WithMany(x => x.NewsItemVideoClips)
.HasForeignKey(x => x.NewsItemId);
this.HasRequired(x => x.VideoClip)
.WithMany(x => x.NewsItemVideos)
.HasForeignKey(x => x.VideoClipId);
//configure table map
ToTable("NewsItemVideoClip");
}
}
The LINQ query:
public IList<NewsItemVideoClip> GetVideoClips(int newsItemId)
{
var query = from nvc in _newsItemVideoClipRepository.GetAll()
where nvc.NewsItemId == newsItemId
orderby nvc.DisplayOrder descending
select nvc;
var newsItemVideoClips = query.ToList();
return newsItemVideoClips;
}
Howcome EF gives me: Invalid column name 'Video_Id'?
Based on your diagram, VideoClip has a VideoId which I guess is your intended foreign key to Video. Video_Id would be the default foreignkey name for the foreign key in the abscence of mapping that would name it otherwise. So probably need a .HasForeignKey(x => x.VideoId); to your VideoClip mapping.