I have the below structure in Entity framework
[Table("Person")]
public class Person
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public long Id{get ;set;}
public string Name{get;set;}
public long DId { get; set; } // this is id from Department Table
[ForeignKey("DId")]
public Department SudentDepartment{get;set;}
}
[Table("Department")]
public class Department
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public long Id{get ;set;}
public string Name { get; set; }
}
Now, I am overriding the SaveChanges method to Audit changes in Audit Table at field level. I am unable to get old and new value of Department in ChangeTracker as it is navigation property. This is required because in Audit table I need to save Departname instead of Id.
Is there any way I could get the navigation property in ChangeTracker?
Only input I have is that you could try to use a code similar to the one on Audit.EntityFramework library.
Check the GetForeignKeysValues code here:
https://github.com/thepirat000/Audit.NET/blob/master/src/Audit.EntityFramework/EntityKeyHelper.cs#L145
Related
I created a asp.net mvc4 Internet Application.
There was a UsersContext class in Models folder. I tried to add a POCO in this class.
[Table("Book")]
public class Book
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int BookId { get; set; }
public string BookName { get; set; }
}
And then I added a DbSet in UsersContext.
When I run the application using the default connection string.
Data Source=(LocalDb)\v11.0;Initial
Catalog=aspnet-MvcApplication2-20161129121332;Integrated
Security=SSPI;AttachDBFilename=|DataDirectory|\aspnet-MvcApplication2-20161129121332.mdf
The 6 tables were created.
But if I change the connection string to Server=.; DataBase=demo; User ID=abc; Pwd=123456. All tables were created but the Book table.
I want to know why this happened, and how can I do to make the Book table be created?
EF7 fills contained navigation properties even when not requested. For example, I have the below entities.
public class Employee
{
public int EmployeeId { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
public int DepartmentId { get; set; }
public Department Department { get; set; }
}
public class Department
{
public int DepartmentId { get; set; }
public string Name { get; set; }
public ICollection<Employee> Employees { get; set; }
}
My fetch query is as below.
ctx.Employees.Where(e => e.Gender == "Male").Include(e => e.Department)
I get Department property of Employee object filled – which is as expected as I have an Include for Department. I find that Department.Employees is also filled but partially (only with male employees). I have not specified an Include for Department.Employees, but it is still getting populated. Is this behavior by design? Is there any way to avoid fetching Department.Employees in this scenario?
I am using EF7 NuGet package with version 7.0.0-rc1-final.
That is the normal behavior of EF. When you execute your query, all the entities you load is going to be attached to your context. So, EF is not executing another query and loading Department.Employees partially, those employees were loaded earlier when you execute your query. In summary, when you consult Department.Employees navigation property, EF is going to fill that property with the employees that you load with your query filtering by Gender.
Update:
As I pointed out in my comment above, Lazy Loading is not supported in EF7. If you want to avoid that Json.NET serializes that property, you can use the attribute JsonIgnore over that property or you can create a custom class (DTO) to project your query and fill only the properties that you need. I also recommend take a look to Automapper if you decide to use this last solution.
I am a newbie to Entity framework and I was confused when i want to update an existing Entity with Navigation Property.
Here is an Model class I am using.
public class Institution
{
[Key]
public int ID { get; set; }
public int Code { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Key { get; set; }
public string PreferURL { get; set; }
public virtual ICollection<EntitlementEntity> Entitlement{ get; set; }
}
I did an MVC HttpPost back in the edit action with auto deserialization from SCOTT HANSELMAN(http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx).
Everything works fine if I ignore Navigation PropertiesICollection<EntitlementEntity> Entitlement in the form; once included, an exception throw.
{"An object with the same key already exists in the ObjectStateManager.
The ObjectStateManager cannot track multiple objects with the same key."}
I finally got it work as below.
https://gist.github.com/pwang2/8363266
What i am reluctant to do is we already have all the relations in the original Institution Entity with Navigation Property, but here I have to set the institution relation for every Entitlement Entity again.
My questions are:
Is it possible to update the institution entity as well as its Navigation Properties at the same time.
If not, what's the best practice if I want a more concentrate UI result to allow update both the institutional information and its entitlement at the same time?
I have the following models:
public class SomeForm
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public IList<FacilityContactInformation> OriginatingFacilities { get; set; }
public IList<FacilityContactInformation> DestinationFacilities { get; set; }
}
public class FacilityContactInformation
{
public FacilityContactInformation()
{
Id = -1;
}
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[MaxLength(50)]
public string Owner { get; set; }
}
I am using automatic migrations to gen and re-gen the database schema.
This generates the error "Foreign key 'FK_dbo.FacilityContactInformations_dbo.SomeForm_SomeForm_Id ' references invalid column 'SomeForm_Id' in referencing table 'FacilityContactInformations'.
Could not create constraint. See previous errors.
I suspect the root cause is that EF tries to generate a FK FK_dbo.FacilityContactInformations_dbo.SomeForm_SomeForm_Id for both lists
Is there any way to keep using automatic migrations, but get this to generate a FK that works? It would seem like the FK should include the list name and generate two properties on FacilityContactInformations OR should generate an intermediate table to join on.
When you have 2 navigational properties that link to the same class, you should override OnModelCreating method of your dbcontext class. Then add this code into the OnModelCreating:
modelBuilder.Entity<SomeForm>
.Hasmany<FacilityContactInformation>(x => x.OriginatingFacilities);
modelBuilder.Entity<SomeForm>
.Hasmany<FacilityContactInformation>(x => x.DestinationFacilities);
This is because EF cannot determine the correct keys if the nav. prop. link to the same class.
please have a look at the following POCOs:
public class Country
{
[Key]
public Guid ID { get; set; }
[Required]
public virtual Currency Currency { get; set; }
}
public class Currency1
{
[Key]
public Guid ID { get; set; }
public virtual ICollection<Country> Countries { get; set; }
}
public class Currency2
{
[Key]
public Guid ID { get; set; }
}
I am not exactly sure what I need navigation properties like the ICollection in Currency1 for. If it comes to EF CodeFirst I see no difference in the database structure created. The tables of Currency1 and Currency2 look pretty much the same to me. So why or when does it make sense to add this extra property?
Of course, just thinking of the POCOs I understand that I can't access any countries from a Currency2 object. For example:
var a = currency1.Countries; // works fine
var b = currency2.Countries; // does not even compile
But is this the only difference? In other words: If I do not need to access countries from a Currency2 object, there is no need to add a corresponding navigation property in the Currency2 class for the purposes of EF? Kind of confused here...
Navigation properties are used either for direct access (as you described) or in linq-to-entities queries. If you don't plan to use it you can remove it from your model. Just be aware that you need a navigation property on at least one side to be able to model database realation using the code first approach.