Why is Entity Framework navigation property null? - linq

I am use code first model with a relationship below
public class ApplicationUser : IdentityUser
{
public string UserFirstName { get; set; }
public string UserLastName { get; set; }
public string UserSchool { get; set; }
public UserProfileData UserProfileData { get; set; }
public int? MedicalSpecialtyId { get; set; }
public virtual MedicalSpecialty MedicalSpecialty { get; set; }
// public int? AnalyticsDataId { get; set; }
// public ICollection<AnalyticsData> AnalyticsDatas { get; set; }
}
public class MedicalSpecialty
{
public int Id { get; set; }
public string Description { get; set; }
// public int ApplicationUserId { get; set; }
public virtual ApplicationUser ApplicationUser { get; set; }
public ICollection<ProgramDetailData> ProgramDetailDatas { get; set; }
}
And when I try to get a User's associated MedicalSpecialty object it is NULL
userSpecialtyName = currentUser.MedicalSpecialty.Description;
BUT when I run this code above it the currentUser.MedicalSpecialty is no longer NULL. What happened?? Somehow that LINQ query woke up the object and filled it with data
var userSpecialtyId = currentUser.MedicalSpecialtyId;
userSpecialtyName = _medicalSpecialtyRepository.Find
(x => x.Id == userSpecialtyId).FirstOrDefault().Description;
userSpecialtyName = currentUser.MedicalSpecialty.Description;

Related

Web API JSON deserialization converting value issue

I am trying to insert JSON data into my models via EF 6. I am getting this error;
Inner Exception is {0}System.ArgumentException: Could not cast or convert from System.String to EPINMiddleWareAPI.Models.Serial.
konum: Newtonsoft.Json.Utilities.ConvertUtils.EnsureTypeAssignable(Object value, Type initialType, Type targetType)
konum: Newtonsoft.Json.Utilities.ConvertUtils.ConvertOrCast(Object initialValue, CultureInfo culture, Type targetType)
konum: Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType)
Message ---
{0}Error converting value "c57a55b5-b2d4-46e7-86e0-cc13726ca8a7" to type 'EPINMiddleWareAPI.Models.Serial'. Path 'coupons[0].serials[0]', line 1, position 310.
Here is my model structure:
public class ConfirmResponse
{
public int Id { get; set; }
public string referenceId { get; set; }
public string version { get; set; }
public string signature { get; set; }
public string paymentID { get; set; }
public string productCode { get; set; }
public string currency { get; set; }
public string ApplicationCode { get; set; }
public double unitPrice { get; set; }
public double totalPrice { get; set; }
public string purchaseStatusCode { get; set; }
public DateTime? purchaseStatusDate { get; set; }
public DateTime? requestDateTime { get; set; } = DateTime.Now;
public string merchantProductCode { get; set; }
public List<Coupon> coupons { get; set; }
}
public class Coupon
{
public int Id { get; set; }
public int ConfirmResponseID { get; set; }
public List<Serial> serials { get; set; }
public List<Pin> pins { get; set; }
public virtual ConfirmResponse confirmResponse { get; set; }
}
public class Serial
{
public int Id { get; set; }
public string serials { get; set; }
public int CouponID { get; set; }
public virtual Coupon coupons { get; set; }
}
My sample JSON:
"{\"referenceId\":\"0000000046\",\"paymentId\":\"MDO1037624\",\"productCode\":\"001002461285\",\"quantity\":\"1\",\"currency\":\"TL\",\"unitPrice\":\"46,47\",\"totalPrice\":\"46,47\",\"merchantProductCode\":\"\",\"purchaseStatusCode\":\"00\",\"purchaseStatusDate\":\"2019-03-17T20:58:48Z\",\"coupons\":[{\"serials\":[\"c57a55b5-b2d4-46e7-86e0-cc13726ca8a7\"],\"pins\":[\"T6VC-XC6X-3H6JS-NVWL-93PCa\"]}],\"version\":\"V1\",\"signature\":\"2f961c7dbc32c3bc128b6e69d19e8e1a\",\"applicationCode\":\"52e7cf966b724749a7c4efadc3727ed7\"}"
How can I fix this problem? I would like to insert this JSON into my database tables. I am using EF 6.
edit:
This model structure solved my problem. Now I can insert serials and pins into database.
public class ConfirmResponse
{
public int Id { get; set; }
public string referenceId { get; set; }
public string version { get; set; }
public string signature { get; set; }
public string paymentID { get; set; }
public string productCode { get; set; }
public string currency { get; set; }
public string ApplicationCode { get; set; }
public double unitPrice { get; set; }
public double totalPrice { get; set; }
public string purchaseStatusCode { get; set; }
public DateTime? purchaseStatusDate { get; set; }
public DateTime? requestDateTime { get; set; } = DateTime.Now;
public string merchantProductCode { get; set; }
public List<Coupon> coupons { get; set; }
}
public class Coupon
{
public int Id { get; set; }
public int ConfirmResponseID { get; set; }
public List<string> serials { get; set; }
public List<string> pins { get; set; }
public virtual ConfirmResponse confirmResponse { get; set; }
public List<string> StringsSerial
{
get { return serials; }
set { serials = value; }
}
public List<string> StringsPin
{
get { return pins; }
set { pins = value; }
}
[Required]
public string Serial
{
get { return String.Join(",", serials); }
set { serials = value.Split(',').ToList(); }
}
[Required]
public string Pin
{
get { return String.Join(",", pins); }
set { pins = value.Split(',').ToList(); }
}
}
Thanks in advance.
you're json is wrong
take a look into the coupons array, you initialize the serials array with an string/guid and not with a model of serial
it should be
"coupons": [{
{
"serials": [{
"serials": "c57a55b5-b2d4-46e7-86e0-cc13726ca8a7"
}
],
}
}
]...
I guess for Pins the same

ef6 query many to many using bridge

how do I query this many to many relationship? I am starting with ACCOUNT, and want to return the ExecutingBroker.Firm associated with it.
I am starting with Account, then I guess drill to MANAGER, then to MAPPING_MANAGER, then to EXECUTINGBROKER.
Here is my query so far...
var student = dbEF.Accounts
.Where(x => x.AccountNumber == acctNum)
.Select(x => new DTOCrmDetails()
{
AccountNumber = x.AccountNumber,
AccountName = x.AccountName,
DateOpened = x.DateOpened,
CommissionId = x.CommissionId,
Commission = x.Commission,
ManagerID = x.ManagerID,
ManagerName = x.Manager.ManagerName,
Manager = x.Manager,
Employees = x.Manager.Employees,
WireInstructionsUSD = x.Manager.WireInstructionsUSDs
}).FirstOrDefault();
below is the code that was generated from ef from existing database.
public partial class Manager
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Manager()
{
this.Accounts = new HashSet<Account>();
this.Employees = new HashSet<Employee>();
this.WireInstructionsUSDs = new HashSet<WireInstructionsUSD>();
this.Mapping_ManagersExecutingBrokers = new HashSet<Mapping_ManagersExecutingBrokers>();
}
public int ManagerID { get; set; }
public string ManagerName { get; set; }
public string Strategy { get; set; }
public string ManagerShortCode { get; set; }
public Nullable<int> WireInstructionsUsdID { get; set; }
public Nullable<int> WireInstructionsForeignID { get; set; }
public string MEtradingPlatform { get; set; }
public string EtradingCostResp { get; set; }
public string NotesManager { get; set; }
public bool MainStrategy { get; set; }
public string PathPayments { get; set; }
public string PathEtrading { get; set; }
public string LEI { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Account> Accounts { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Employee> Employees { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<WireInstructionsUSD> WireInstructionsUSDs { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Mapping_ManagersExecutingBrokers> Mapping_ManagersExecutingBrokers { get; set; }
}
}
{
using System;
using System.Collections.Generic;
public partial class Mapping_ManagersExecutingBrokers
{
public int Mapping_ManagersExecutingBrokersId { get; set; }
public Nullable<int> ManagerID { get; set; }
public Nullable<int> ExecutingBrokersId { get; set; }
public virtual ExecutingBroker ExecutingBroker { get; set; }
public virtual Manager Manager { get; set; }
}
}
public partial class ExecutingBroker
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public ExecutingBroker()
{
this.Mapping_ManagersExecutingBrokers = new HashSet<Mapping_ManagersExecutingBrokers>();
}
public int ExecutingBrokersId { get; set; }
public string Firm { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Mapping_ManagersExecutingBrokers> Mapping_ManagersExecutingBrokers { get; set; }
}
You have to go through Mapping_ManagersExecutingBrokers, since you've modelled it that way.
Keep in mind that you have a collection of Firms, since it's a many-to-many-relationship.
.Select(account => new { Firms = account.Manager.Mapping_ManagersExecutingBrokers
.Select(meb => meb.ExecutingBroker.Firm) });

EF 5 ENUM with Navigation

I'm trying to use Enum support with EF 5 and dot.NET 4.5.
The situation I have is the following.
POCO:
public partial class tbl_pp_Message
{
public tbl_pp_Message()
{
this.tbl_pp_MessageDistribution = new List<tbl_pp_MessageDistribution>();
}
public int MessageId { get; set; }
public string Subject { get; set; }
public string From { get; set; }
public string Body { get; set; }
public int PriorityId { get; set; }
public System.DateTime CreateDate { get; set; }
public int CreateById { get; set; }
[ForeignKey("PriorityId")]
public virtual tbl_pp_MessagePriority tbl_pp_MessagePriority { get; set; }
public virtual ICollection<tbl_pp_MessageDistribution> tbl_pp_MessageDistribution { get; set; }
}
public partial class tbl_pp_MessagePriority
{
public tbl_pp_MessagePriority()
{
this.tbl_pp_Message = new List<tbl_pp_Message>();
}
public int MessagePriorityId { get; set; }
public string Description { get; set; }
public Nullable<int> DisplayOrder { get; set; }
public bool ShowAlert { get; set; }
public virtual ICollection<tbl_pp_Message> tbl_pp_Message { get; set; }
}
With the code listed above NOT using an ENUM the world is happy.
When I try to add an Enum the POCO will look like this.
[Flags]
public enum MessagePriorityEnum : int
{
NONE = 0,
Urgent = 1,
Normal = 2,
Low = 3
}
public partial class tbl_pp_Message
{
public tbl_pp_Message()
{
this.tbl_pp_MessageDistribution = new List<tbl_pp_MessageDistribution>();
}
public int MessageId { get; set; }
public string Subject { get; set; }
public string From { get; set; }
public string Body { get; set; }
public MessagePriorityEnum PriorityId { get; set; }
public System.DateTime CreateDate { get; set; }
public int CreateById { get; set; }
[ForeignKey("PriorityId")]
public virtual tbl_pp_MessagePriority tbl_pp_MessagePriority { get; set; }
public virtual ICollection<tbl_pp_MessageDistribution> tbl_pp_MessageDistribution { get; set; }
}
This will not work during a save because it doesn't like the ForeignKey attribute. This error will be thrown during a save.
Schema specified is not valid. Errors:
(129,6) : error 0112: The types of all properties in the Dependent Role of a referential constraint must be the same as the corresponding property types in the Principal Role. The type of property 'PriorityId' on entity 'tbl_pp_Message' does not match the type of property 'MessagePriorityId' on entity 'tbl_pp_MessagePriority' in the referential constraint 'tbl_pp_MessagePriority_tbl_pp_Message'.
If the navigation for tbl_pp_MessagePriority is removed from tbl_pp_Message POCO. And the navigation removed from tbl_pp_MessagePriority POCO back to tbl_pp_Message then it works.
With out the navigation removed it will generate a SQL statement like this.
insert [dbo].[tbl_pp_Message]
([Subject],
[From],
[Body],
[PriorityId],
[CreateDate],
[CreateById],
[tbl_pp_MessagePriority_MessagePriorityId])
values ('Test ENUM EF Code First 5.0' /* #0 */,
'Daniel.Bivens' /* #1 */,
'Test 01 Enum Body - The Magic Unicorn Edition' /* #2 */,
2 /* #3 */,
'2013-05-23T10:52:09' /* #4 */,
5 /* #5 */,
null)
select [MessageId]
from [dbo].[tbl_pp_Message]
where ##ROWCOUNT > 0
and [MessageId] = scope_identity()
It would be ok if the tbl_pp_MessagePriority_MessagePriorityId was not added to the insert.
What can be done to keep the navigaion in EF code first while using ENUM support? Is there a DataAnnotation or a Mapping API?
Please post any suggestions you may have. This project is not using an EDMX/T4 template.
Working POCO:
public partial class tbl_pp_Message
{
//public tbl_pp_Message()
//{
// this.tbl_pp_MessageDistribution = new List<tbl_pp_MessageDistribution>();
//}
public int MessageId { get; set; }
public string Subject { get; set; }
public string From { get; set; }
public string Body { get; set; }
public MessagePriorityEnum PriorityId { get; set; }
public System.DateTime CreateDate { get; set; }
public int CreateById { get; set; }
//[ForeignKey("PriorityId")]
//public virtual tbl_pp_MessagePriority tbl_pp_MessagePriority { get; set; }
//public virtual ICollection<tbl_pp_MessageDistribution> tbl_pp_MessageDistribution { get; set; }
}
public partial class tbl_pp_MessagePriority
{
//public tbl_pp_MessagePriority()
//{
// this.tbl_pp_Message = new List<tbl_pp_Message>();
//}
public int MessagePriorityId { get; set; }
public string Description { get; set; }
public Nullable<int> DisplayOrder { get; set; }
public bool ShowAlert { get; set; }
//public virtual ICollection<tbl_pp_Message> tbl_pp_Message { get; set; }
}
The working POCO would be ok if no navigation was needed.
The thing I was missing was setting the look-up table primary key to the same ENUM type instead of an int.
Working POCO with ENUM and navigation.
public partial class tbl_pp_Message
{
public tbl_pp_Message()
{
this.tbl_pp_MessageAction = new List<tbl_pp_MessageAction>();
this.tbl_pp_MessageAttachment = new List<tbl_pp_MessageAttachment>();
this.tbl_pp_MessageDistribution = new List<tbl_pp_MessageDistribution>();
}
public int MessageId { get; set; }
public string Subject { get; set; }
public string From { get; set; }
public string Body { get; set; }
public MessageTypeEnum TypeId { get; set; }
public System.DateTime CreateDate { get; set; }
public int CreateById { get; set; }
[ForeignKey("TypeId")]
public virtual tbl_pp_MessageType tbl_pp_MessageType { get; set; }
public virtual ICollection<tbl_pp_MessageAction> tbl_pp_MessageAction { get; set; }
public virtual ICollection<tbl_pp_MessageAttachment> tbl_pp_MessageAttachment { get; set; }
public virtual ICollection<tbl_pp_MessageDistribution> tbl_pp_MessageDistribution { get; set; }
}
public partial class tbl_pp_MessageType
{
public tbl_pp_MessageType()
{
this.tbl_pp_Message = new List<tbl_pp_Message>();
}
[Key]
public MessageTypeEnum MessageTypeId { get; set; }
public string Description { get; set; }
public Nullable<int> DisplayOrder { get; set; }
public bool ShowAlert { get; set; }
public virtual ICollection<tbl_pp_Message> tbl_pp_Message { get; set; }
}

Using Linq to populate a class

I am getting a weird behavior. I have a class that I created that is used to format data comping from a data entity into a data grid. I am a using a linq query to create a list of the class type from a list of the entity type. Some of the properties of the class are accessible from the linq query but other give me an error. (AMNotStartedPortalDisplay' does not contain a definition for 'ChecklistStatusID'). So my question is why can linq access some properties but not others? I see no reason why this should be happening.
Here is my class:
public class AMWOTPortalDisplay
{
public string DisplayName { get; set; }
public string LOB { get; set; }
public string DisplayProjectPackages { get; set; }
public string ChecklistStatus { get; set; }
public int ChecklistStatusID { get; set; }
public string InstallDate { get; set; }
public string dateToYellow { get; set; }
public string dateToRed { get; set; }
public string ApplicationManager { get; set; }
public string ApplicationManagerLanID { get; set; }
public int ApplicationManagerUserID { get; set; }
public string ImpersonatedManager { get; set; }
public string ImpersonatedManagerLanID { get; set; }
public int ImpersonatedManagerUserID { get; set; }
public string DelegateName { get; set; }
public string DelegateLanID { get; set; }
public int DelegateUserID { get; set; }
public string WOTAssignee { get; set; }
public int ChecklistID { get; set; }
public string DisplayLinkText { get; set; }
public string LinkTextURL { get; set; }
public string rowColor { get; set; }
public string rowTextColor { get; set; }
}
And here is the linq query as I have it so far:
var portaldisplay = checklists
.Select(c => new AMNotStartedPortalDisplay
{
DisplayName = string.Format("{0} ({1})", c.Application.Name, c.Application.ApplicationID),
LOB = c.Application.LOB,
ChecklistStatus = c.ChecklistStatusType.TypeName,
ChecklistStatusID = c.ChecklistStatusTypeID
});
Thanks,
Rhonda
Be careful with your types:
public class AMWOTPortalDisplay
And then:
Select(c => new AMNotStartedPortalDisplay { ... })
It looks like your query should probably be:
Select(c => new AMWOTPortalDisplay { ... })

Entity Framework also Linq advice needed

i have got on my DB 3 tables
movies, workers, workermovies ( this is the Relationship table )
public class Movie
{
public Movie()
{
Genres = new List<Genre>();
Formats = new List<Format>();
ProductionCompanies = new List<ProductionCompany>();
Workers = new List<Worker>();
}
public int Id { get; set; }
public string Title { get; set; }
public DateTime ReleaseDate { get; set; }
public string StoryLine { get; set; }
public int RunTime { get; set; }
[ForeignKey("MPAARateId")]
public MPAARate MPAARate { get; set; }
public int MPAARateId { get; set; }
public byte[] ImageData { get; set; }
public string ImageMimeType { get; set; }
public DateTime CreatedDate { get; set; }
public string OfficialSite { get; set; }
public int Budget { get; set; }
public int StatusId { get; set; }
public virtual ICollection<Genre> Genres { get; set; }
public virtual ICollection<Format> Formats { get; set; }
public virtual ICollection<ProductionCompany> ProductionCompanies { get; set; }
public virtual ICollection<Worker> Workers { get; set; }
}
public class Worker
{
public int Id { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public DateTime Birthday { get; set; }
public string Biography { get; set; }
public string BornName { get; set; }
public double Height { get; set; }
public DateTime? Died { get; set; }
public byte[] ImageData { get; set; }
public string ImageMimeType { get; set; }
public bool IsActor { get; set; }
public bool IsDirector { get; set; }
public bool IsWriter { get; set; }
public bool IsProducer { get; set; }
public bool IsStar { get; set; }
public virtual ICollection<Movie> Movies { get; set; }
}
in this Relation i got the movieId and the workerId
but i also got some more fields if the person acted or writen or producer etc.
how do i define the relation entity class if needed
and when i want to get just the ppl that acted in the movie how do i wrote such a linq
query
You need to introduce an additional entity in your model WorkerMovie and convert the many-to-many relationship between Worker and Movie into two one-to-many relationships - one between Worker and WorkerMovie and the other between Movie and WorkerMovie. A sketch:
public class WorkerMovie
{
[Key, Column(Order = 0)]
public int WorkerId { get; set; }
[Key, Column(Order = 1)]
public int MovieId { get; set; }
public Worker Worker { get; set; }
public Movie Movie { get; set; }
public bool WorkedAsActor { get; set; }
public bool WorkedAsWriter { get; set; }
public bool WorkedAsProducer { get; set; }
// etc.
}
public class Movie
{
// ...
public virtual ICollection<WorkerMovie> WorkerMovies { get; set; }
// remove ICollection<Worker> Workers
}
public class Worker
{
// ...
public virtual ICollection<WorkerMovie> WorkerMovies { get; set; }
// remove ICollection<Movie> Movies
}
If you want only to find the workers who were actors in a particular movie with a movieId you can write:
var workersAsActors = context.WorkerMovies
.Where(wm => wm.MovieId == movieId && wm.WorkedAsActor)
.Select(wm => wm.Worker)
.ToList();
Here is another answer to a very similar question with many more examples of possible queries: Create code first, many to many, with additional fields in association table

Resources