Entity Framework - Database generated identity is not populated after save if it is not the key of the entity - entity-framework

I have a model like
public class MyEntity
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Required]
public int Id { get; set; } // Id
[Required]
[Key]
public System.Guid GUID { get; set; }
}
The GUID property is the PK by design, but I have a db generated Id property that I use within my code to determine if the object is a new object that hasn't been saved yet.
When I save this object with Entity Framework, the Id property does not get back populated as normally happens for database generated properties (although usually these are keys). I have to query the DB for the object and grab the ID manually. It seems EF only back populates Key properties on SaveChanges.
Is there any way to get EF to automatically populate the Id property here? Setting it as the Key is not an option, I have dozens of tables that are FK'd to the GUID property and for good reason.
EDIT: I have discovered that the package https://entityframework-extensions.net/ is handling my save changes. If I use the standard EF savechanges it works, but not with the extensions version.

Disclaimer: I'm the owner of Entity Framework Extensions
It was indeed an issue in our library. This scenario was not yet supported for EF6.
However, starting from the v4.0.50, it should now work as expected.

Related

EF Query pulls null when dbase shows populated field

I've got an issue with EF Core in which I loop through a list of objects and create related elements in another list. As I process the first object everything is great, it is added to the list properly and looks great when we pull the information from the database.
At the start of the code for processing each object, I grab more detailed information from the database about that object (it's related objects and such). When the query executes for the second object information in another object changes. It changes a foreign key to be null for the first object instead of the proper value. If I look in the database as that occurs, the foreign key is set properly. This change in the foreign key shown in the query causes it to show as dirty in the context.
Therefore, when we finish processing the second object and make an update to the database, the system commits the (now) null foreign key to the database. This causes all sorts of issues, as you would expect.
partial object definition below
public partial class CommandType
{
public int? FkATSId { get; set; }
public virtual ATST FkATS { get; set; }
}
public partial class ATST
{
public virtual ICollection<FAT> FAT{ get; set; }
}
public partial class FAT
{
public int? FkDTRTId{ get; set; }
public virtual DTRT FkDTRT { get; set; }
}
public partial class DTRT
{
public int? FkFDTid{ get; set; }
public virtual FDT FkFDT{ get; set; }
}
public partial class FDT
{
...
}
The value that gets comes back as a change to null is FkFDTid in the DTRT.
if we are processing 5 of the items, 4 will end up with a null id and the last one will have the proper foreign key. If we processed 10, 9 would have the bad id and the last one would be good.
If I go through the code in the debugger and keep an eye on the context directly, the value does not come back from the query as null and so things work fine. But, only if I keep the context open in the locals tab of VS.
Does anyone have any ideas?
It turns out the issue was a discrepancy between the database and the entity framework context. The database for one of the items had the foreign key as not unique, but the context, for some reason, had it as unique.
We were able to store values into the database but if we queried the database and brought more than one record that had the same foreign key value, EF would think to itself: This can't be, that foreign key must be unique. I'll set the first one I grabbed to be null. Voila, they're not unique. Oh, because I changed that foreign key, the record is now dirty and will be committed to the database when we do a save changes.
The takeaway from this: if you see values that are different from what is stored in the database after you query the database, check foreign key and uniqueness constraints.

key by navigation property using annotation (entity framework)

I have a class as
public class fooClass
{
[Key]
public virtual fooRefClass staff { get; set; }
public Int64 fooProp1{ get; set; }
public DateTime fooProp2{ get; set; }
}
when i do the migration it give me error as "no key defined" but i had added the key attonation already .My intention is to make the referenced entity "fooRefClass " as primary key as well as foreign key, i know there is a way by mentioning the attribute id of the referenced entity and writing the foreign-key annotate over there, but i want to deal with entity directly ,rather than id only, how can i attain this functionality ,please help me with the issue.
Since there seems to be confusion, I decided to write an answer as well.
With the class you defined, EF would expect a table like
fooClass(bigint fooRefClass_Id, bigint fooProp1, datetime fooProp2);
... which is not valid, because this has no key column (the key annotation on your navigation property does nothing, because you see, it won't appear in the table... it will just tell EF there is a relationship to this table, and because you didn't provide a FK, it creates one to create this relationship). You also can't create this relationship yourself in your current model, because you don't even have a FK... how would you access a property you know nothing about, just that it will be created at some point (usually upon model creating with first accessing the database).
You have to tell EF you want the property, that will be created, to also be a key, not only a foreign key. You can do this by simply creating the property yourself and telling EF you want to use this, for example (I'm not too familiar with Data Annotations, I usually use Fluent API, so please excuse maybe occuring errors)
[Key, Foreign Key(fooRefClass)]
public Int64 StaffId {get; set;}

Auditing many-to-many relationships in Entity Framework?

I have been reading some artices about using the RelationshipManager to gain access to the entries that have related data. It is still unclear to me what the best way to audit when an entity whose related data is added or updated.
Sample Classes:
public class Rfi
{
public Guid Id {get;set;}
public string Number {get;set;}
public virtual ICollection<Attachment> Attachments {get;set;}
}
public Class Attachment
{
public Guid Id {get;set;}
public string Name {get;set;}
public string Description {get;set;}
public string FileName {get;set;}
public string Path {get;set;}
}
Sample Mappings:
public class RfiMapping: EntityTypeConfiguration<Rfi>
{
public Rfimapping()
{
HasMany(r => r.Attachments).WithMany().Map(m =>
{
m.MapLeftKey("RfiId");
m.MapRightKey("AttachmentId");
m.ToTable("Rfi_Attachments");
});
}
}
I am using the Repository and Unit Of Work patterns. My UoW inherits from DbContext. A repository call may look like this:
public void AddAttachmentToRfi(Attachment attachment, Guid rfiId)
{
var rfi = _rfiRepository.FindById(rfiId);
rfi.Attachments.Add(attachment);
_rfiRepository.UnitOfWork.Commit();
}
Is it possible , in an overridden SaveChanges method, to figure out that an Attachment entity was added to an Rfi entity? When I traverse the, say ChangeTracker.Entries, I am not seeing its state being set to modified. Which makes sense, because I am only adding to the relationships and not the entity directly.
I know to cast my DbContext to an IObjectContextAdapter, but I am not sure what I need to do with the RelationshipManager to get the changes made to any of the relationships. I am also curious to know if I were to update an Attachment's Description property later on, if I can still see what changes were made to any related data.
My goal with this is, the user interface for the Rfi allows users to attach files (Rfi is obviously not the only entity that can have attachments). I need to show a history of everything that happens to an Rfi. This means if an attachment is added I need to audit it. If the attachment's data is updated, I need to audit those changes and show that they were updated via the Rfi interface. This may get complicated if that attachment is shared with another entity, but I will cross that road later.
As you say you are not changing any of the entities only the relationship between them.
EF will then convert this to an insert into or delete from the Rfi_Attachments table.
One way to audit this is to add a database trigger that writes an entry to a log table, each time an entry is added or deleted.

EF code-first foreign key

I have a class Question
CompareItems store CurrentQuestion-to-OtherQuestion compare information.
public class Question
{
public virtual ICollection<QuestionMark> CompareItems { get; set; }
}
public class QuestionMark
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public int Question { get; set; } //Store ID of OtherQuestion
public decimal Mark { get; set; }
}
When I delete some question A I need that all QuestionMark where QuestionMark.Question == A.Id also deleted, because it's no need to have compare information if question not exist. How it possible to do that without making QuestionMark.Question an entity? Maybe EF have some rule in Fluent-API to set that QuestionMark.Question is foreign key on Question entity?
I don't wont to make QuestionMark.Question as entity because it will need to change current solution lot - is a first. Also, question is a quite heavy entity, and to load it multiple time to assign value or delete or something else will be press on performance
I think it's possible to change app to use Entities instead of id, because EF use lazy loading by default and it will not caused performance problems. And I think that using just id instead of entity possible with some fluent API settings or attribute.
If you do not want to make a navigational property Question in QuestionMark class then you need to manually create a foreign key with "cascade delete". Then when every a question is deleted the database will delete the related QuestionMark records.
However this approach has a problem with EF. Because EF does not know there is a "cascade delete" relationship among these entities. So there can be inconsistencies within the locally tracked entities in EF.
You have not given a reason as to why you do not want to map the relationship in EF but I highly advice you against it.

Automatic Model Validation When Generating the Models using Entity Framework Database First Approach

Consider the following property UserName of a Model Class. You can see that the validation criteria are added over it manually.
[Required]
[StringLength(100, MinimumLength = 6)]
public string UserName { get; set; }
Now again consider the following code:
public string UserName { get; set; }
The same property without the validators. Now when I am generating the model class using Entity Framework Database first approach I am getting the later result (means a property without having validators). But in the database there are constraints added over each attribute.
So is there any tool/way that I can use those constraints and generate the model class having properties like shown in code 1 (that is property with validators).
No there is no ready to use tool which would add these attributes for you. You can modify T4 template to create these attributes for you but for that you need to understand how EF metadata are stored. You can add attributes yourselves manually in buddy classes.