Need some advice for a Many to many fluent code problem - entity-framework

Hi I got 2 Many to Many table linked with a joint table.
UsagerEW <-> UsagerPermissionEW <-> Permission
This is an old DB and the UsagerEW do not have a Id column but a CodeInt instead.
When I scaffold this database, EF7 create the 3 tables and relations between all. But do not skip the join table to create a "pure" many to many relationships.
So I add 2 virtual properties in each table:
In permission: public virtual ICollection UsagerEWs { get; } = new HashSet();
In UsagerEW: public virtual ICollection Permissions { get; } = new HashSet();
Then I add this fluent code to create a Many2Many relationship:
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)
);
That code works great. I can read UsagerEW with permission directly. The only time this code failed is when I try to add permission to a UsagerEW.
I try to do: context.usagerEW.Permissions.add(new permission)
Or I try to create the UsagerPermission joint object and update the middle table directly. In the 2 case, I got this error:
The column name 'permissionId' is specified more than once in the SET clause or column list of an INSERT.
And to SQL code generated is
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();
So something is wrong with my fluent code.
Any idea??

Related

Entity Framework Core Nullable FK not getting records

I have an OrderHeader table and OrderLines table. I also have a Rate table. Both OrderHeader and OrderLines can have rates. So this Rate table is setup as:
RateId
RateValue
OrderHeaderId
OrderLineId
So if we're adding header rates the OrderHeaderId is filled in and OrderLineId is null. When adding line rates the opposite happens.
My OnModelCreating() has:
modelBuilder.Entity<Rate>(entity =>
{
entity.HasOne(d => d.OrderHeader)
.WithMany(p => p.Rates)
.HasForeignKey(d => d.OrderHeaderId)
.HasContraintName("FK1")
.IsRequired(false);
entity.HasOne(d => d.OrderLines)
.WithMany(p => p.Rates)
.HasForeignKey(d => d. OrderLineId)
.HasContraintName("FK2")
.IsRequired(false);
}
When I query for a OrderLine record the Rates has 0 records in it, but in the DB there are 2 records for this OrderLineId.
I'm not really sure what else I should be looking for. I thought the .IsRequired(false) would have fixed the issue since in Rates table those FK's can have null values but it didn't.
Related rows are only loaded if you request them, otherwise querying a single entity instance might load your whole database into memory. Read EF Core Loading Related Data
Also the FK between Rate and OrderLines should be on (OrderHeaderId,OrderLineId) to ensure that the Rate's OrderLines all belong to the Rate's OrderHeader. And for similar reasons the primary key of OrderLines should also be (OrderHeaderId,OrderLineId).

Error Deleting Child Entity in Entity Framework 6

We are using EF6 database first with AspNet Identity. AspNetUsers is our table of customers. It extends AspNet IdentityUser. Each customer has many devices. The abbreviated table structures are
CREATE TABLE [dbo].[AspNetUsers] (
[Id] NVARCHAR (128) NOT NULL
);
CREATE TABLE [dbo].[Devices] (
[DeviceID] INT IDENTITY (1, 1) NOT NULL,
[UserId] NVARCHAR (128) NOT NULL
);
ALTER TABLE [dbo].[Devices]
ADD CONSTRAINT [FK_Devices_AspNetUsers] FOREIGN KEY ([UserId]) REFERENCES [dbo].[AspNetUsers] ([Id]);
CustomersContext OnModelCreatingspecifies the relationship between AspNetUsers and Devices.
modelBuilder.Entity<ApplicationUser>()
.HasMany(e => e.Devices)
.WithRequired(e => e.User)
.HasForeignKey(e => e.UserId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Device>()
.HasKey(e => e.DeviceId);
modelBuilder.Entity<Device>().Property(e => e.UserId)
.IsRequired()
.HasMaxLength(450);
The following code
var userDevices = user.Devices.ToList();
foreach (Device device in userDevices)
{
user.Devices.Remove(device);
}
await customersContext.SaveChangesAsync();
fails with the error
Cannot insert the value NULL into column 'UserId', table 'Customers.dbo.Devices'
That appears to be trying to remove the relationship without deleting the device. How do I delete a device using EF?
You want to delete the device. It is not possible to just remove it from the Devices list, as it cannot exist stand-alone by itself. It has a non-nullable foreign key (from column UserId) referencing AspNetUsers(Id) - deletion would break referential integrity.
To delete the device, add following statement inside foreach loop to successfully delete the devices associated with a user.
customersContext.Entry(device).State = EntityState.Deleted;
Another way would be to place following code inside foreach loop to delete the device directly from the device repository itself, instead of going through Devices navigation property available on ApplicationUser entity:
customersContext.Devices.Remove(device);
If you don't want to delete the records from the Devices table and just want to remove the relationship between AspNetUsers and all the Devices in one go, then you can assign null to the navigation property and save the changes. This will remove the relation between the entities without physically deleting the records from database.
user.Devices = null;

Need proper syntax using EF6 Fluent API between 2 tables using PK and FK

If you all need more details I will send them for sure. Here is a screen shot containing 2 tables:
Basically this is what looks like in SQL today:
I am trying to use the fluent API for the relationship but not sure how to do it.
Table 1 has a PK and a FK.
Table 2 does not have a PK, only FK.
Below is an example of what I need but this code applies to a different set of tables. I am trying to get the "relationship" syntax correct for the scenario described here:
this.ToTable("Server");
//primary key
this.HasKey(t => t.serverId);
//properties
...
//relationships
this.HasMany(n => n.NetworkAdapters)
.WithRequired(s => s.Server)
.HasForeignKey(s => s.serverId)
.WillCascadeOnDelete(true);
Thank you
Without the primary key on table 2 you are most likely looking for a One-to–Zero-or-One relationship. You might possibly be requiring both ends which I will describe too.
One-to–Zero-or-One
// Configure the primary key for Table1
modelBuilder.Entity<Table1>()
.HasKey(t => t.networkAdapterId);
// Map one-to-zero or one relationship
modelBuilder.Entity<Table2>()
.HasRequired(t => t.Table1)
.WithOptional(t => t.Table2);
One-to-One
// Configure the primary key for the Table1
modelBuilder.Entity<Table1>()
.HasKey(t => t.networkAdapterId);
// Map one-to-one relationship
modelBuilder.Entity<Table2>()
.HasRequired(t => t.Table1)
.WithRequiredPrincipal(t => t.Table2);
See here for more details

How do I tell Entity (Code First) to not send the Key ID field to the database?

My code:
Models.Resource r = new Models.Resource();
r.Name = txtName.Text;
r.ResourceType = resTypes.Find(rt => rt.Name == "Content");
r.ResourceContents.Add(_resourceContent.Find(rc => rc.ID == _resourceContentID));
ctx.Resource.Add(r);
ctx.SaveChanges();
ctx.SaveChanges() causes the error:
Cannot insert explicit value for identity column in table 'Resources' when IDENTITY_INSERT is set to OFF.
Looking at what's being sent to SQL:
ADO.NET:Execute NonQuery "INSERT [dbo].[Resources]([ID], [Name], [Description], [IsOnFile],
[ContentOwnerAlias], [ContentOwnerGroup], [ResourceTypes_ID])
VALUES (#0, #1, #2, #3, #4, #5, NULL)"
My POCO Resource has ID as a Key:
public partial class Resource
{
public Resource()
{
}
[Key]
public int ID { get; set; }
And my Map code:
public class ResourceMap : EntityTypeConfiguration<Resource>
{
public ResourceMap()
{
// Primary Key
this.HasKey(t => t.ID);
How do I tell Entity to not send the Key ID field to the database?
If your PK is generated by the database (like an identity) you have to configure it in your Map.
public class ResourceMap : EntityTypeConfiguration<Resource>
{
public ResourceMap()
{
// Primary Key
this.HasKey(t => t.ID);
this.Property(t => t.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
You do not need the HasKey(t => t.ID) Fluent API mapping or the [Key] Data Attribute because by convention EF will assume that an integer field named ID is the key and is database generated.
As an aside, I'd recommend that when you are not following conventions you should choose one method or the other - otherwise you are repeating yourself and when you want to change something you need to change it in 2 places.
I'm not sure why the field in the database isn't already database generated - maybe when you define the field via the fluent api you have to specify that too. What I do know is that in order to make EF change a key field to be database generated you will need to drop the table.
So - rollback the migration or drop the table / database, then remove the data attribute, remove the fluent mapping and recreate.
This issue is currently on a "backlog" in the entity framework. If you want to vote for it you can do that here: Migrations: does not detect changes to DatabaseGeneratedOption
Other References:
Identity problem in EF
Switching Identity On/Off With A Custom Migration Operation

How do i assosiate my PICO class with a specific table in my database with Entity Framework 5

I have a table in my db (a many to many table) that two classes A and B have created like this.
this.HasMany(t => t.TrafficImageQuestions)
.WithMany(t => t.TrafficImages)
.Map(m =>
{
m.ToTable("TrafficImage_Answers");
m.MapLeftKey("TrafficImagesGuid");
m.MapRightKey("TrafficImageQuestionsId");
});
Now i would like to assosiate my custom class to this same table "TrafficImage_Answers", the class offcause have the left and right key and then also a 3. custom property.
(i did add the column to the database "Answer")
public class TrafficImageAnswer
{
public System.Guid TrafficImageGuid { get; set; }
public int TrafficImageQuestionId { get; set; }
public byte Answer { get; set; }
}
I am doing this as i want entity model to keep track of my many to many relationship of A and B and still be able to look up the 3. property Answer that is in the database.
What i have tried
I tried to do the following:
this.Property(t => t.TrafficImageQuestionId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
this.Property(t => t.TrafficImageGuid)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
// Table & Column Mappings
this.ToTable("TrafficImage_Answers");
But i get that the table already exists, logic. I need to tell it that it just should use that table and not try to create it.
(im doing this with DB mitigrations in EF 5 and Package manager).
That is not supported. If you want to have additional field in the junction table for many-to-many relation you cannot map it as many-to-many any more. Each table can be mapped only once but mapping table to entity and to many-to-many relation in the same time makes it mapped twice.
You must change your TrafficImageQuestions and TrafficImages to use one to many relations with TrafficImageAnswer instead of many-to-many relation with each other.