Enitify Framework code first: Updating Entity With required related navigational property - c#

My model looks like this
public Class Address
{
public int Id {get;set;}
/*Props here*/
}
public Class Person
{
public int Id {get;set;}
public String Name {get;set;}
[Required]
public Address Address{get;set;}
/*More props*/
}
Now suppose i have created a person with proper address, in future when i try to update person like this
var person= db.Persons.FirstOrDefault(p=>p.Id=1234);
person.Name="Foo";
db.SaveChanges();
It gives error saying Address is required.
So to avoid this iam including Address property too while loading Person Entity
var person= db.Persons.Include(p=>p.Address).FirstOrDefault(p=>p.Id=1234);
person.Name="Foo";
db.SaveChanges();
Is there any way i can update person Without including Address.

It's the model validation of DbContext which complains apparently. So, one solution would be to switch off this validation:
dbContext.Configuration.ValidateOnSaveEnabled = false;
The other option is to introduce a foreign key property:
public class Person
{
public int Id {get;set;}
public String Name {get;set;}
public int AddressId {get;set;}
public Address Address {get;set;}
/*More props*/
}
You can omit the [Required] attribute here because EF will detect the relationship as required by convention (due to the non-nullable FK property). This works also with enabled validation.
The behaviour is a bit confusing since EF doesn't send a change of the FK column to the database, so there is not really a constraint violation and the Update command executes fine. I guess that the validation just checks the state of the model in memory (invalid, because Address is null) and not the state the model would have in the database when SaveChanges did execute (valid, because FK is correctly set).

If you want the address to be automatically loaded by EF 4.1 you have to make the Address-porperty virtual:
public virtual Address Address{get;set;}
EF will then lazy-load the address when needed.

Related

Entity Framework 1:0..1 (One to zero or one) relationship using Data Annotations

Trying to do something that I believe should be simple.
Customer
------
CustId
BillingId
ShippingId
...other customerInfo
Address
------
Id
...other addressinfo
I have the corresponding POCOs
public class Customer {
[Key]
public int CustId {get;set;}
[Column("BillingId")]
[ForeignKey("BillingAddress")
public int? BillingId {get;set;}
public virtual Address BillingAddress{get;set;}
[Column("ShippingId")]
[ForeignKey("ShippingAddress")
public int? ShippingId {get;set;}
public virtual Address ShippingAddress{get;set;}
...others...
}
public class Address {
[Key]
public int AddressId{get;set}
... others...
}
The BillingId and ShippingId are nullable because the customer may or may not have set an address yet. I'd assume with EF that if the values are null, the ShippingAddress and BillingAddress values should also be null. When I take a look at the object I'm getting back when running the application, all of the data on my Customer object is set but on the ShippingAddress/BillingAddress fields, in debug mode when I inspect the object, I get the below error:
BillingAddress = '((System.Data.Entity.DynamicProxies.CustomerD_E865AA67CAAA399D4F193A2439775301DFD2F05115619BC048699B20BF6F7B11)details).BillingAddress'
threw an exception of type 'System.InvalidOperationException'
A same error appears for the ShippingAddress field. The application actually continues to run, the exception only gets thrown when inspecting in debug more. For the particular inspected object, the ShippingId and BillingId are populated correctly.
Not sure why this is happening given my setup.
one possible reason is: your repository is registered as singleton in DI configure.
another possible reason: add ForeignKey and InverseProperty to navigation properties
public class Customer {
[Key]
public int CustId {get;set;}
//[Column("BillingId")]//not necessary if real column is same as property
public int? BillingId {get;set;}
[ForeignKey("BillingId")]
[InverseProperty("Customer")]
public Address BillingAddress{get;set;} //no need to be virtual
//[Column("ShippingId")]
public int? ShippingId {get;set;}
[ForeignKey("ShippingId")]
[InverseProperty("Customer")]//InverseProperty: Specifies the inverse of a navigation property that represents the other end of the same relationship.
public Address ShippingAddress{get;set;} //no need to be virtual
...others...
}
try Scaffold-DbContext in a new project to validate your pocos:
https://learn.microsoft.com/en-us/ef/core/miscellaneous/cli/powershell#scaffold-dbcontext
Scaffold-DbContext "your connection string" -DataAnnotations -OutputDir "Models" -Force

EF Navigation Property in Database first

I have a database and I want to know how to map the relationships via code. I'm not sure if I understand exactly how this works.
Suppose I have two classes:
public class Address
{
[Key]
public int AddressID {get;set;}
public String Street {get;set;}
}
public class Shipment
{
[Key]
public int ShipmentID {get;set;}
public int ShipToAddressID {get;set;}
public virtual Address ShipToAddress {get;set;}
}
I have a few questions:
Does the navigation property merely give me access to the dbset of Address?
It seems that is not the case. However, if not, how do I specify which property is the foreign key on which the relationship exists? eg: How do I tell this navigation property that it should match the Address entities based on the AddressID property ?
Again, I'm doing this all via code. So I'm mapping the properties in the OnModelCreating call in the context. So please make suggestions/provide answers with that in mind.
You are in need of the HasRequired, WithMany, and HasForeignKey configuration methods.
EntityTypeConfiguration<Shipment> config = modelBuilder.Entity<Shipment>();
config
.HasRequired(s=>s.ShipToAddress)
.WithMany()
.HasForeignKey(s=>s.ShipToAddressID)
.WillCascadeOnDelete(false);

Entity Framework 6 Lazy Loading returns null

I have a class with the following properties
public class Booking
{
public long BookingId {get;set;}
public string RoomNumber {get;set;}
[ForeignKey("BookingCustomer")]
public long? BookingCustomerId {get;set;}
public virtual Customer BookingCustomer {get;set;}
}
public class Customer
{
public long CustomerId {get;set;}
public string FirstName {get;set;}
}
if in a method I reference properties of the customer class am getting object null reference exception while BookingCustomerId is populated.i.e.,
hotel.BookingCustomerId=2
For instance,
string customerFirstName = hotel.BookingCustomer.FirstName;
if I peek at the hotel.BookingCustomer i get null
How do I go about this Lazy Loading?
If the related entity is coming back as null this means the relationship as understood by entity framework can't find any related entities.
It appears you are using data annotations to flag properties with properties such as foreign keys. You may also need to flag primary keys with the [key] attribute.
You will also need to add a related booking entity to your customer data.
Alternatively you can you the fluent api to do the following in your context.
// Configure the primary key for the Booking
modelBuilder.Entity<Booking>()
.HasKey(t => t.BookingID);
modelBuilder.Entity<Booking>()
.HasRequired(t => t.customer)
.WithRequiredPrincipal(t => t.booking);
More on the fluent a picture here:
https://msdn.microsoft.com/en-us/data/jj591620.aspx#RequiredToRequired
Lazy loading implies that the related objects are retreived when the getter of that object is used for the first time.
At just that time a query to the database is executed to retreive for that object ,for example Hotel.BookingCustomer.
Try to see if the query is indeed executed e.g. with Sql Server profiler.
Examine the query to makes sure everything is correct
If you can't see the query triggered, try to it without the virtual keyword (eager loading) and see if it's working then.

Deleting a child object of an aggregate root in Entity framework

This might be asked before but I can't seem to find a solution on the site so here we go:
Here is an oversimplified version of my domain model. I have 2 classes representing 2 tables in the database:
public Class Person
{
public int Id { get; set;}
public string Name { get; set;}
public virtual List<Contact> Contacts { get; set;}
public void AddContact(string value)
{
//some validation code
Contacts.Add(new Contact(value));
}
public void DeleteContact(Contact contact)
{
//some validation code
Contacts.Remove(contact);
}
}
public Class Contact
{
public int Id { get; set;}
public string Value { get; set;}
public virtual Person Person { get; set;}
public int PersonId { get; set;}
}
Now Person is my aggregate root here. I am trying to follow the DDD principal by only making the repository for the aggregate root. Adding contact works fine.
The problem I have is when deleting the contact. It gives the error:
The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.
Is there anyway past it. If the relation property is non-nullable shouldn't entity framework automatically delete the contact.
Now I know that deleting from the collection is not the same as deleting it from the context but I don't want to reference DbContext from my domain model.
I only have PersonRepository.
Kindly provide a solution or help me understand if I am getting any concept wrong.
That's a common problem when doing DDD with EF. Two solutions worked well for me so far:
Return the removed instance from your DeleteContact method. The method is most probably called from an application service which holds a repository. You can then use it to remove the instance from DbContext.
If you use domain events you can use one to notify others about contact removal. You could then place a handler for this event in the infrastructure layer which would remove the contact from DbContext.
It looks like you're having the same problem as in this post. Basically, when you remove the contact from the collection, you are not actually deleting it; you are only orphaning it, and in the process, setting its PersonId to null (which is not possible for an int, of course).
One possible solution is to make PersonId nullable in the Contact class:
public int? PersonId { get; set; }
Then, in your DbContext, override SaveChanges to automatically delete the orphaned records:
public override int SaveChanges()
{
foreach (Contact contact in Contacts.Local.Where(c => c.PersonId == null))
{
Contacts.Remove(contact);
}
return base.SaveChanges();
}
Disclaimer: I haven't tested that code but hopefully it is a good starting point.

Cyclical reference error in MVC3 & Entity Framework 4

I admit using MVC3/EF4 has been a breeze and the context:models work better then I'd hoped (though I'm always leary of constructs/frameworks that make things happen behind some curtain, but hey I'm old school grey beard), and all went well until I hit this issue.
I've seen many postings related to this issue but don't know how to solve it in my case. Each table(entity) has an employeeID field and it can (and usually is) a different employee for most records in each table. Apparently only one table in the DbContext can have a 'virtual employee employee' (or whatever I choose to name it) defined or else I get the dreaded "cyclical reference error". Ideally I'd like all three tables to have it so I can easily access the employees name. I may have to override the OnModelCreating() but that's (fluent API) totally out of my league. Any EF gurus out there????
Models:
class meeting{
int meetingID; //key
string description {get;set;}
int employeeID {get;set;} // who scheduled
public virtual employee employee {get;set;}
public virtual ICollection<agenda> agendas {get;set;}
}
class agenda{
int agendaID {get;set;} // key
int employeeID {get;set;} // initiator
public virtual employee employee {get;set;}
public virtual ICollection<actionItem> actionItems {get;set;}
}
class actionItem{
int actioItemID {get;set;} //key
string description {get;set;}
int employeeID {get;set;} // action item lead
public virtual employee employee {get;set;}
}
class employee{
int employeeID {get;set;}//key
string name {get;set;}
}
context:
public class meetings:DbContext{
public DbSet<meeting> meetings {get;set;}
public DbSet<agenda> Agendas
public DbSet<actionItem> actionItems{get;set;}
}
I assume you're getting this error on serialization of your models. Most people use a second set of models to abstract from the EF models, but if you want to stick with those, use the approach from this answer to get rid of your cyclical reference problem:
EF 4.1 - Code First - JSON Circular Reference Serialization Error

Categories