Is this normal Entity Framework behaviour - oop

I have two one to many relations between the following classes
public class SiteMember
{
public int SiteMemberID { get; set; }
public virtual List<FriendshipInvitation> InvitationsSent { get; set; }
public virtual List<FriendshipInvitation> InvitationsReceived { get; set; }
}
public class FriendshipInvitation
{
public int InvitingUserID { get; set; }
public SiteMember InvitingUser { get; set; }
public int InvitedUserID { get; set; }
public SiteMember InvitedUser{ get; set; }
}
Then in controller I have the following code (which loads one SiteMember from db):
SiteMember sm = repoSiteMember.GetUserByName(User.Identity.Name);
at this point
sm.InvitationsReceived.InvitingUserId = 1;
sm.InvitationsReceived.InvitingUser = null
Then I have the following line (which loads all SiteMembers from db):
IEnumerable<SiteMember> all = repoSiteMember.GetAll();
after which
sm.InvitationsReceived.InvitingUserId = 1
sm.InvitationsReceived.InvitingUser = proxy to SiteMember object.
My question is: Is this normal behaviour? I'm quite sure I can "fix" null pointer with include statement, but I find it weird that loading all elements from db actually changes the state of object. (null => proxy). Should the proxy be there from the beginning?
Edit:
Just to confirm, include statement does solve the problem of null reference, but that was not the question here.
DataContext.Members
.Include("InvitationsSent.InvitedUser")
.Include("InvitationsReceived.InvitingUser")
.FirstOrDefault(e => e.UserName == userName);
Edit2: Methods included now.
public SiteMember GetUserByName(string userName)
{
return base.DataContext.Members.FirstOrDefault(e => e.UserName == userName);
}
public IEnumerable<SiteMember> GetAll()
{
return base.DataContext.Members.ToList();
}
Edit3: You may need that to recreate the model.
modelBuilder.Entity<FriendshipInvitation>()
.HasRequired(e => e.InvitedUser)
.WithMany(e => e.InvitationsReceived)
.HasForeignKey(e => e.InvitedUserID)
.WillCascadeOnDelete(false);
modelBuilder.Entity<FriendshipInvitation>()
.HasRequired(e => e.InvitingUser)
.WithMany(e => e.InvitationsSent)
.HasForeignKey(e => e.InvitingUserID);
modelBuilder.Entity<FriendshipInvitation>()
.HasKey(e => new { e.InvitingUserID, e.InvitedUserID, e.InvitationNo });

Yes, the different behaviour is normal and it occurs because of Relationship Fixup.
When you load only one SiteMember with FirstOrDefault the two collections InvitationsSent and InvitationsReceived will be loaded as well as soon as you access them (or inspect them in the debugger) because they are marked as virtual and lazy loading will apply. But the FriendshipInvitations in those collections won't lazily load the InvitingUser or the InvitedUser because these navigation properties are not marked as virtual.
Say, SiteMember 1 that you load with FirstOrDefault has an invitation received from SiteMember 2 and no invitation sent. So, InvitationsReceived will contain one element and InvitationsSent will be empty. That element - a FriendshipInvitation entity - will have InvitingUser as 2 and InvitedUser as 1. The InvitingUser will be null in that case because it can't be lazily loaded (since it isn't virtual) and the SiteMember 2 isn't loaded yet into the context. (InvitedUser however will be a dynamic proxy to SiteMember 1 because you already have loaded the SiteMember 1, see next paragraph.)
However, if you load all SiteMembers with ToList() the SiteMember 2 will be loaded as well into the context with the query executed by ToList(). EF will set the InvitingUser 2 automatically to the already loaded entity which is called Relationship Fixup. It is not loaded by lazy loading of the InvitingUser navigation property because lazy loading isn't supported for a not virtual property.
To have a consistent behaviour and not rely on Relationship Fixup alone I would suggest that you mark the InvitingUser and InvitedUser navigation properties as virtual as well.

Related

EF Core explicit ignore relation

public class Unit
{
Public int Id { get; set; }
Public virtual ICollection<Element> Elements { get; set; }
}
public class Element
{
public int Id { get; set; }
public virtual Unit Unit { get; set; }
}
We use a API call to get all Elements with related Units.
Like this:
Context.Elements.Include(o => o.Unit);
Our expectation was that only Elements would have a Unit. However the Units do also have Elements
{
"Id": 1,
"Unit": {
"Id": 1,
"Elements":[...]
}
}
How do we exclude the Elements from Unit.Elements?
EF Core populate entity's navigation properties if related entities already loaded in the memory.
Context.Element.Include(e => e.Unit)
Line above will load all Element entities in the memory, so it will populate Unit.Elements as well.
Entity Framework Core will automatically fix-up navigation properties
to any other entities that were previously loaded into the context
instance. So even if you don't explicitly include the data for a
navigation property, the property may still be populated if some or
all of the related entities were previously loaded.
EF Core 2.1 now supports lazy loading which probably could answer your question, but, as I mentioned above, in your case all Elements already loaded in the memory.
Loading Related Data - Lazing Loading
There is currently no solution for this.
As pointed out here there is a workaround available:
Context.Elements.Include(o => o.Unit).Select(o => new Element()
{
Id = o.Id,
Unit = o.Unit
});

method within model in MVC

I have a model in my MVC app, 'designation'. I have a method getdesig() to simply return all of the designations. I originally had this in my controller but moved to my model recently, with the aim of decluttering my controller and making it thinner. Is this model a logical place to put such a method?
public class designation
{
[Key]
public int DesignationID { get; set; }
public string DesignationName { get; set; }
public virtual ICollection<user> users { get; set; }
private ClaimContext db = new ClaimContext();
public List<designation> getdesig()
{
{
return (from c in db.designations
select c).ToList();
}
}
}
yes, however in more complicated scenarios where conditions exists the controller is the spot to determine "What" needs to be loaded or "how much" needs to be loaded based off the scenario/arguments. In this very simple example it is fine as you are just dumping all the data without regard to any context.
It is a good practice to keep your ViewModels as simple and specific to the View as possible, the ViewModel's job is to simply be a common store to drive the view. The view relies on the model to be set with the appropriate data, it is the job of the controller to determine context and what should be populated in the model.

Initializing referenced objects in entity framework unit of work

I have a class in Entity framework 5 (using MVC 4):
public class JobFunction
{
public int Id { get; set; }
public string JobFunctionName { get; set; }
public int StatusId { get; set; }
public Status JFStatus { get; set; }
}
In my OnModelCreating method, I establish a FK relationship with the Status table as follows:
modelBuilder.Entity<JobFunction>().HasRequired(a => a.JFStatus).
WithMany().HasForeignKey(u => u.StatusId).WillCascadeOnDelete(false);
In my controller, I get a list of JobFunction objects as follows:
List<JobFunction> jfList = uow.JobFunctionRepository.GetAll().ToList<Catalog>();
where uow is my Unit of Work object, and JobFunctionRepository is defined. When I examine any JobFunction object in jfList, I see the following in my watch window:
Id: 1
JfStatus: null
JobFunctionName: "Manager"
StatusId: 2
Note that JFStatus is null. My question is: what provisions do I make in my code to initialize JFStatus to the appropriate Status object (based on the value of StatusId), during my GetAll call?
Thanks in advance.
-Zawar
You need some instrument to apply eager loading when you load the data through your repository. For example you could give your GetAll method a parameter list of expressions for the navigation properties you want to include in your query:
using System.Data.Entity;
//...
public IQueryable<JobFunction> GetAll(
params Expression<Func<JobFunction, object>>[] includes)
{
IQueryable<JobFunction> query = context.JobFunctions;
foreach (var include in includes)
query = query.Include(include);
return query;
}
Then you call it like so:
List<JobFunction> jfList = uow.JobFunctionRepository
.GetAll(jf => jf.JFStatus)
.ToList();
The JFStatus property should be filled now.

NHibernate not updating all properties of entities

I'm experiencing an odd problem with FluentNHibernate: when I save my entity, one of the (reference) properties is not updated. Other properties, both fields and references, are updated, and the failing property is correctly mapped (retrieving entities works like a charm).
A (slightly simplified) description of what I'm doing:
Into my MVC action method, an InputModel is bound and set. It has a property for the TypeID, where I wish to set the Type of my entity (let's call the entity type Thing).
A new Thing object is created, and the simple properties of the InputModel is copied over. For a couple of complex properties, among them the Type property which isn't working and another property which is, the following is done:
2.1. The correct ThingType is fetched from the repository, based on the provided type id.
2.2. The type is set (using thing.Type = theType) on the new Thing object.
The Thing that I want to update is fetched from the repository, based on the id on the input model (not the same id as the TypeID).
All properties, complex and other, are copied over from the new thing (created by me) to the original one (fetched from db).
The original Thing is saved, using session.Save();.
As stated above, it's only one property that isn't working - other properties, following (as far as I can tell) the exact same pattern, work. I've also debugged and verified that the original Thing has the correct, updated Type when it is passed to session.Save().
I have no idea where to start troubleshooting this...
Update: The classes are plain POCOs:
public class Thing
{
public int ID { get; set; }
public string SomeSimpleProp { get; set; }
public ThingType Type { get; set; }
public OtherEntity OtherReference { get; set; }
}
public class ThingType
{
public int ID { get; set; }
public string Name { get; set; }
}
My exact mappings (except for the names of types and properties) are these:
// In ThingMap : ClassMap<Thing> constructor:
Id(t => t.ID).Column("ThingID");
Map(t => t.SomeSimpleProp);
References(t => t.Type).Column("ThingTypeID");
References(t => t.OtherReference).Column("OtherReferenceID");
// In ThingTypeMap : ClassMap<ThingType> constructor:
Id(t => t.ID).Column("ThingTypeID");
Map(t => t.Name);
As I said, OtherReference is updated correctly while Type is not. They are mapped identically, so I don't see how this could be a mapping error.
You should specify <many-to-one .... cascade="save-update"/> in order to update references.

Association properties on Entity not loaded for server-side validation

Consider the following situation. I have an Entity named ProductSupplier that is a Presentation Model. It is created by doing an inner join of Products and Suppliers, and creating a new projection from a Linq statement. The ProductSupplier projection also creates a list of PartType objects, which is also a Presentation Model.
public partial class ProductSupplier
{
private IEnumerable<PartType> _partTypes;
[Key]
public int ProductSupplierKey { get; set }
[Include]
[Association("ProductSupplier_PartType", "ProductSupplierKey", "ProductSupplierKey")]
public IEnumerable<PartType> PartTypes
{
get { return _partTypes ?? (_partTypes = new List<PartType>()); }
set { if (value != null) _partTypes = value; }
}
}
public partial class PartType
{
[Key]
public int PartTypeKey { get; set; }
[Key]
public int ProductSupplierKey { get; set; }
public int PartQuantity { get; set; }
}
I want to have a validation that is no ProductSupplier can be have more than 10 separate parts. This means that all PartQuantities for all PartTypes that belong to a ProductSupplier should be summed, and the total cannot exceed 10.
For this, I created a custom validator:
public static ValidationResult ValidatePartTotals(ProductSupplier productSupplier, ValidationContext validationContext)
{
if (productSupplier.PartTypes.Sum(p => p.PartQuantity) > 10)
return new ValidationResult("Must be less than 10 parts total.");
return ValidationResult.Success;
}
This works fine when validation is called from the client-side. The problem I'm having is that when the validator is run from the server-side, the IEnumerable is always empty.
I have tried adding [RoundTripOriginal] to the PartQuantity, and to various other properties, such as all the Key fields, but it still is an empty list when done on the server side.
How can I access these PartType objects when validation is run on the server?
Unfortunately, you don't have any guarantees as to the state of the object graph when it gets to you on the server. RIA optimizes things so you'll only see modified entities. One solution would be to use composition. It will make sure the whole graph is passed around, but it has other effects that may not be what you want. Another option would be to hydrate the graph in your update method, then perform validation, and throw a ValidationException as necessary.