I have three small model classes and although two of them does works one is not and I can't figure out why. I found several solutions but neither of them helped me. First of all, code first approach was used in the project.
So, the main problem is that the PK in the Coupon class is not set to autoincrement value. I refer to the tables from Server Explorer and see PK's properties. Realized that other two classes PK's properties are set as Is Identity to True and Identity Increment = 1 whereas in the Coupon's PK's property they are set as Is Identity to False and Identity Increment to 0.
I think the problem is somewhere there and below you can find the small model class I am having trouble with.
public class Coupon
{
public Coupon()
{
footballMatches = new List<FootballMatch>();
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CouponId { get; set; }
public int UserId { get; set; }
public virtual List<FootballMatch> footballMatches { get; set; }
}
Ask me more if you need further information.
Thanks !
Not expected that, but I found the solution in such a silly way. The solution to my problem was just re-adding the key. At first, I did not agree with marc_s because I also tried re-adding before. Apparently, I did in a wrong way when I firstly tried re-adding.
What I made wrong is converting int to string then converting back to int while I did not touch the name of the instance, which is CouponId. That did not work. However, and sadly, I also had to change the name of the instance as well to make it work. I changed the line public int CouponId to public string CouponName then convert back to the actual name. Now it shows the expected behaviour.
Briefly, the simple solution is to change the key both variable and name and alter them to their actual names again. That simply.
By the way, while doing them please do not forget to update your migrations between each step. So the workflow is like Change->Update->Change Back->Update.
Hope that can help others who went through the same trouble.
Related
Using Microsoft.EntityFrameworkCore version 5.0.7 and Npgsql.EntityFrameworkCore.PostgreSQL version 5.0.7, I'm currently stuck trying to remove a relationship and have that change stored. Assume two models:
public class Banana {
public int Id { get; set; }
public Consumer? Consumer { get; set; }
}
public class Consumer {
public int Id { get; set; }
}
I'm able to assign a consumer just fine using
myBanana.Consumer = dbContext.Consumers.First(row => row.Id == 1);
dbContext.Update(myBanana);
dbContext.SaveChanges();
and that works just fine - the database is updated accordingly. However, once that is stored, trying to remove the reference again using
myBanana.Consumer = null;
dbContext.Update(myBanana);
dbContext.SaveChanges();
fails. After saving, the old value is still in the database, not null as I would expect. Interestingly, other changes to the banana are saved just fine.
I'm not sure if I'm hitting a weird issue with Nullables, or if I'm just missing something, so I'd appreciate some hints.
If you want to continue using auto-generated foreign key properties, you have to make sure that the navigations are loaded. If they are lazy-loaded by default and you don't manually load them, the property will already be null before you try to assign null, so EF can't observe a change.
Loading the navigation with .Include(banana => banana.Consumer) works, and so does loading it via dbContext.Entry(myBanana).Reference(banana => banana.Consumer).Load(). After the relevant navigation items are loaded, myBanana.Consumer = null from the example in the question works as expected.
If you have a non-tracking entity to work with (for example because it was generated by Model Binding), you can either get a tracking entity, or change the value of the auto-generated foreign key shadow property directly:
dbContext.Entry(myBanana).Property("ConsumerId").CurrentValue = null;
which also works. This may be a little bit less polished since you depend on a string as the field name to be correct, but it can be a valid option depending on the circumstances.
before you link to another post, i am using migrations and all that i can find don't use the way i have to do it.
first this is homework,
second here is a link to a google drive with the "full" project project fill stuff that was given to help, and a word doc with specifications(but the last one is not as important)
so on to the problem i am tring to do my homework the package manager says this "The entity type 'Categories' requires a primary key to be defined. If you intended to use a keyless entity type call 'HasNoKey()'." almost no matter what i do. i can get it to stop but then the database is not actual made at all.
my teacher is not responing to my emails and the other students in my class that have responed have the same issue, and this is the very beginning of the project and for the last few days i have been stuck here so please help.
i will add edit as questions get asked, i am panicking on getting this done in time so i don't know what is important or not.
First of all, double check you actually set PrimaryKey on your Database table. Then use [Key] attribute from System.ComponentModel.DataAnnotations namespace.
public class Categories
{
[Key]
public string CategoryId { get; set; }
public string Name { get; set; }
}
And also, next time, make sure your ID fields are either numeric or Guid and auto generated by database identity specification.. string Ids are slow for querying db records and to index tables.
Must tell model CategoryId is key. Best to use int as type.
[Key]
public int CategoryId { get; set; }
Having recently moved to C#/.Net Core from other languages, I got stuck on a problem with EF Core that I couldn't figure out from the documentation and hope you may be able to help. In a way this is related but not identical to my previous question .Net Core [FromBody] JArray to ICollection
My database holds a number of appointments that are rendered on a Syncfusion schedule. Attendees can be invited to these appointments. To facilitate that, a list of users is displayed in the editor and a JSON array of guids is transmitted with any insert or update action.
The User entity itself is not available within the scope of the application, so I'd like to persist only their Guids for each appointment. I had foreseen this structure:
Appointments (Start, End, ..., ´ICollection Attendees´)
Attendee would simply consist of AppointmentsId and Guid -
Since any one Guid can only attend each Appointment once, a composite Key made up of these two attributes appeared to be useful.
Any appointment can have none, one or many associated Guids.
In Code, I have this (abbreviated):
public class Appointment
{
public int Id { get; set; }
public DateTime StartTime { get; set; }
public ICollection<Attendee> AttendeeList { get; set; }
[NotMapped]
public List<Guid> PostedAttendeeList { get; set; } // Contains a list of Guids after an Insert/Update POST action from [FromBody]
}
Attendee would simply be made up of the Appointment Id and a Guid of a user.
public class Attendee
{
public Guid Id { get; set; }
public int AppointmentId { get; set; }
}
Attendee's configuration is this:
public class AttendeeConfiguration : IEntityTypeConfiguration<Attendee>
{
public void Configure(EntityTypeBuilder<Attendee> builder)
{
builder.HasKey(x => new { x.Id, x.AppointmentId });
}
}
After receiving a POST from the schedule, ´PostedAttendeeList´ may be empty or contain one or more Guids.
If it is an existing Appointment, ´AttendeeList´ may be empty or contain one or more Guids.
I'm wondering about a few things:
a) is there a better way to go about persisting this kind of data? I've tried to understand Owned Entity Types but failed to see if that would help me here.
b) if this is indeed an ok way to handle this, how can I make sure that ´AttendeeList´ is identical to ´PostedAttendeeList´ after processing, so that all new entries are added and those not present in ´PostedAttendeeList´ are removed through EF Core?
I'm especially confused about whom's responsibility it is to maintain ´AppointmentId´ - I wanted to keep the property visible but I understand that EF would fill that in when operating within the base property? Ie. that within the class ´Appointment´, a ´AttendeeList.Add(new Attendee() { Id = "1234-abcd-..." }´ would automagically fill in the AppointmentId upon saving?
If you read until here and are confused, please take a moment to remember when you started programming - I'm thoroughly confused and unable to come up with a better question. Even if you cannot help out with an answer, maybe you could help me make the question better. Thank you all very much! Any comment with suggestions will result in an update to my question in order to improve it.
Alright, this question has been asked few times. But I can't get to find reason why i am getting this reason in my case. Here is how tables and code is set up.
public class ObjectA{
public int Id;
public virtual ICollection<ObjectB> Bs;
}
public class ObjectB{
public int Id;
public virtual ICollection<ObjectA> As;
}
POCO Mapping on B:
HasMany(As).WithMany(Bs).Map(ToTable("ObjectA_ObjectB_Mapping"))
There are 3 tables:
ObjectA
Id (PK, Int) - AutoIncrement
ObjectB
Id(PK, Int) - AutoIncrement
ObjectA_ObjectB_Mapping
ObjectA_Id
ObjectB_Id
Here is new object is being inserted:
var a = new ObjectA(){}; --> This record already exist in table
var b = new ObjectB(){
A = a; --> Just read only copy
};
When this insert is attempted then I get error about IDENTITY_INSERT is set to OFF.
When I look at SQL generated by EF, I can see that it is trying to insert value in field Id of ObjectB. It seems that there is something that wants to explictly wants to set this Id value. Something I am missing about how many to many relation is set??
Above code is just a very simplified pseudo representatiion, so you can skip comments about telling names, style etc.
Thanks
The easiest fix is to set IDENTITY_INSERT to ON, but I suspect that's not the root problem here, and I wouldn't recommend doing that for obvious reasons, it's just bad practice.
It sounds like EF (or you) is trying to manage the ID's itself, rather than allowing SQL server to. I don't know why, I suspect your actual objects have things going on, but you can also attach the DatabaseGeneratedAttribute (in the System.ComponentModel.DataAnnotations.Schema namespace) to the Id column on your model to force EF to not create an IDENTITY(1, 1) column (or AutoIncrement, depending on DBMS), this creates the requirement for you, the developer to manage the Id column on that model entirely. (Before you can do any SQL operations you have to make sure Id is set properly, including .Add.)
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
This will remove the IDENTITY(1, 1) constraint (or the AutoIncrement, whatever it is). You'll have to run a migration for this to take effect, but once it does you should not get this error anymore. You just have to be very careful to make sure you set Id on everything before calling DatabaseContext.SaveChanges() or DatabaseContext.SaveChangesAsync(). (Whichever you are using.)
You should also explicitly define the KeyAttribute (from System.ComponentModel.DataAnnotations) on your Id columns.
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
I've got some code like this:
Activity[] GetAllActivities() {
using (ScheduleContext ctx = new ScheduleContext())
return ctx.Activities.AsNoTracking().ToArray();
}
The aim to have a very simple in-memory cache of some data: Activities is mapped to a db view which summarizes everything I need.
If I omit AsNoTracking the returned objects are non-deterministically corrupted: properties on the returned objects aren't set correctly, and frequently one object's property value is duplicated in other objects' properties. There's no warning or exception; neither on EF4.3.1 nor EF5rc2. Both CLR 4 and the 4.5 release candidate exhibit the same behavior.
The Activity objects are very simple; consisting solely of non-virtual properties of basic type (int, string, etc.) and have no key nor a relationship with any other entity.
Is this expected behavior? Where can I find documentation about this?
I understand that obviously change tracking cannot work once the relevant DbContext is gone, but I'm surprised the materialized properties are corrupted without warning. I'm mostly worried that I'll forget AsNoTracking somewhere in a more complex scenario and get somewhat plausible but wrong results.
Edit: The entity looks as follows. Thanks Jonathan & Kristof; there is indeed a column that is inferred as the ID!
public class Activity
{
public string ActivityHostKey { get; set; }
public int ActivityDuration { get; set; }
public int ActivityLastedChanged { get; set; }
public string ActivityId { get; set; }//!!!
public string ModuleHostKey { get; set; }
public string ModuleName { get; set; }
...
I think "frequently one object's property value is duplicated in other objects' properties" and that the Activity objects "and have no key" are the key pieces of information here (no pun intended).
When importing a View (which obviously doesn't have a primary key), EF guesses at what the primary key is. If tracking is then enabled, it uses that primary key to make sure only a single copy of each entity is created in memory. This means if you load two rows with the same values for the field EF guessed was the PK, the values for the second row will overwrite the first.
As for the data being "non-deterministically corrupted", that's probably because the database doesn't guarantee the order the rows are returned in, and it's a "last-in-wins" process in EF, so if the order of the records changes from the DB, the record that gets to keep it's values changes too.
Try marking more columns as part of the primary key, or modifying the view (or the DefiningQuery in the EDMX) to contain a column based on the ROW_NUMBER function so you can use it as the primary key.