Entity type "EntityName" has no key defined. Define the key for this entity type - linqpad

I'm using entity framework 4.1 and can't add the connection on linqpad, it says that my child entity doesn't have entity key defined. The message is: "Entity type "CashierPaymentType" has no key defined. Define the key for this entity type."
I think this is happening when my child table has a composite key.
Example:
Table: Cashier
ID INT (Key)
Name VARCHAR(100)
Table: PaymentType
ID INT (Key)
Name VARCHAR(100)
// I think this is the problem!
Table: CashierPaymentType
CashierID INT (key) (foreign key)
PaymentTypeID INT (key) (foreign key)
Price SMALLMONEY
I'm using linqpad 4.35.1
Any help ?

The problem is that you're telling LINQPad to new up your typed DbContext with a provider connection string instead of an Entity Framework connection string.
You'll get the same error in Visual Studio if you construct your typed DbContext with a provider connection string.
A provider connection string is valid only if you're doing code-first (in which case EF infers the model). In your case, the EDM is part of your project and is embedded in your assembly; therefore you must specify the full EF connection string as specified in your app.config so that EF can find it:
metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlClient;provider connection string="data source=.;initial catalog=TestDatabase;integrated security=True;multipleactiveresultsets=True;App=EntityFramework"
Another solution is to use the following connection string, which defers to the app.config file:
name=TestDatabaseEntities
If you do this in LINQPad, make sure you tell it where the app.config file lives, in the textbox provided.
A more subtle point is that the T4 file for your DbContext is different to the default that VS creates, in that your DbContext is missing the following code:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
If this override is present, it gives a more helpful error message if you specify the wrong kind of connection string.

Related

Using DateTime for a SQL Time Column in Entity Framework Core 3.1

Is there a way to make Entity Framework Core let you use a DateTime for a SQL Time column? SQL Server allows you to set a Time column value using a DateTime, but when you try to configure Entity Framework Core to do this, it throws an exception when compiling the model saying that the Database Provider does not support the datatype.
This code throws the exception
public void Configure(EntityTypeBuilder<Category> builder)
{
...
builder.Property<System.DateTime>(x => x.StartTime).HasColumnName(#"StartTime").HasColumnType(#"time").IsRequired()
// HasColumnType matches the type defined in SQL
}
This code works fine, but I'd rather keep HasColumnType accurate so that it doesn't modify the database to use DateTime instead of Time...
public void Configure(EntityTypeBuilder<Category> builder)
{
...
builder.Property<System.DateTime>(x => x.StartTime).HasColumnName(#"StartTime").HasColumnType(#"datetime").IsRequired()
// HasColumnType does not match the type defined in SQL
}
Is there a reason EF Core blocks the ability to do this when SQL allows it?
I ended up resolving this with a Conversion
builder.Property<DateTime>("StartTime").HasColumnName(#"StartTime").HasColumnType(#"time").IsRequired().HasConversion(v => v.TimeOfDay, v => DateTime.Now.Date.Add(v));

UserManager throws exception - Unable to track an entity because primary key property 'Id' is null - after upgrading from .Net Core 2.2 to 3.0

I've used the custom implementation of User which is derivated from IdentityUser using Asp.Net Core Identity:
public class AppUser : IdentityUser
{
...
}
If I call the method:
var identityResult = await UserManager.CreateAsync(user);
I get the error:
System.InvalidOperationException: Unable to track an entity of type 'AppUser' because primary key property 'Id' is null.
It works perfectly with version of Microsoft.AspNetCore.Identity.EntityFrameworkCore - 2.2.0, but after upgrading to 3.0.0 - it doesn't work.
I get same error during testing of the creation of user as well, there I use following UserManager configuration:
https://github.com/aspnet/AspNetCore/blob/c95ee2b051814b787b07f55ff224d03d550aafeb/src/Identity/test/Shared/MockHelpers.cs#L37
There is EF Core 3.0 introduced breaking change String and byte array keys are not client-generated by default which affects entities which use string PK like IdentityUser<string> and IdentityRole<string> and will cause that exception if the PK is not set explicitly.
However the default IdentityUser and IdentityRole classes were also modified to populate the Id property with Guid.NewGuid().ToString() inside class constructors. So normally you shouldn't have that issue except if some code is setting explicitly the Id to null. Anyway, you can switch to old behavior by using the suggestion from the link
Mitigations
The pre-3.0 behavior can be obtained by explicitly specifying that the key properties should use generated values if no other non-null value is set.
e.g. inside context OnModelCreating override, after calling base implementation:
modelBuilder.Entity<AppUser>()
.Property(e => e.Id)
.ValueGeneratedOnAdd();

System.InvalidOperationException in EF core when trying to update

Problem
I am creating a web app in asp.net core with ef core using with Repository pattern. Ii am trying to insert an entity it works fine when i trying to check whether it is already exist in db or then if yes than update the same entity in same api it gives me this error.
System.InvalidOperationException: 'The instance of entity type 'Consultation' cannot be tracked because another instance of this type with the same key is already being tracked. When adding new entities, for most key types a unique temporary key value will be created if no key is set (i.e. if the key property is assigned the default value for its type). If you are explicitly setting key values for new entities, ensure they do not collide with existing entities or temporary values generated for other new entities. When attaching existing entities, ensure that only one entity instance with a given key value is attached to the context.'
Image
code
insert api
[HttpPost]
public ApiResponse InsertConsultation([FromBody] Consultation consultation)
{
if (!ModelState.IsValid)
{
return new ApiResponse(StatusCodes.Status400BadRequest, error: "error");
}
var consult = _consultationService.GetConsultationById(consultation.Id);
if (consult !=null)
{
_consultationService.UpdateConsultation(consultation);
return new ApiResponse(StatusCodes.Status200OK, success: "isSuccess");
}
_consultationService.InsertConsultation(consultation);
return new ApiResponse(StatusCodes.Status201Created, success: "isSuccess");
}
The update process is
1- Retrieve the object which is consult in your code:
var consult = _consultationService.GetConsultationById(consultation.Id);
2- make change to the retrieval object (copy content from consultation to consult) you don't have it.
3- update the object consult
4- save change.
Maybe try this for the line before SaveChanges().
_context.AddOrUpdate(entity);
This needs the System.Data.Entity.Migrations namespace.
Your question might already be answered here:
Update Row if it Exists Else Insert Logic with Entity Framework

Breeze JS Query before calling SaveChanges causes failure

I have the following very standard Breeze API Controller endpoint in my app:
public SaveResult SaveChanges(JObject saveBundle)
{
return _contextProvider.SaveChanges(saveBundle);
}
My backend database uses int IDs that are configured as identities.
When called from a client with a valid change set, all is well.
However, if, prior to the call to my _contextProvider.SaveChanges(saveBundle) function, I make a query of any sort. For example:
public SaveResult SaveChanges(JObject saveBundle)
{
int incomingUserId = Convert.ToInt32(saveBundle["entities"][0]["Id"]);
AspNetUser EditedUser = (from u in Context.AspNetUsers where u.Id == incomingUserId select u).FirstOrDefault();
// ......
// do something with the EditedUser (like validations of any sort)
// ......
return _contextProvider.SaveChanges(saveBundle);
}
the save fails with error:
Saving or accepting changes failed because more than one entity of type 'xxxx.App_Data.AspNetUser' have the same primary key value. Ensure that explicitly set primary key values are unique. Ensure that database-generated primary keys are configured correctly in the database and in the Entity Framework model. Use the Entity Designer for Database First/Model First configuration. Use the 'HasDatabaseGeneratedOption" fluent API or 'DatabaseGeneratedAttribute' for Code First configuration.
Given what I am doing, is this expected behavior? Is there any other way to do an initial, separate query just prior to the SaveChanges call without upsetting something and making the query fail?
You'll need to create a second Context for performing the query. In the code you have above, the EditedUser object is being cached in the Context, because that's what EF does. Then, when _contextProvider.SaveChanges(saveBundle) is called, the contextProvider tries to create an object with the same type and same key in the same Context. Hence the error.
This SO post gives some hints about creating the second Context.

Connection String Issues With Entity Framework Context And Deleting

I have a simple find delete case:
var query = CompanyUsers
.Where ( cu => cu.eMail.Contains( "123#email.com") || cu.eMail.Contains( "456#email.com"))
ServicesEntities se = new ServicesEntities();
se.DeleteObject( query );
ServiceEntities is a EntityFramework 4.1 DLL. The only thing in the DLL is the EF model.
When I try to delete I get:
"ArgumentException: The specified named connection is either not found in the configuration, not intended to be used with the EntityClient provider, or not valid."
If I try adding the name of the connection string in the app.config file like this:
ServicesEntities se = new ServicesEntities("ServicesEntities");
I get: ArgumentException: Format of the initialization string does not conform to specification starting at index 0.
How can I use my EF model and perform deletes using the conext. Is it possible to pass through the connection string that LINQPad appears to be creating in the properties tab or at the minimum use the one from the app.config?