Reputation: 12852
I have a Card class:
public class Card
{
public Card(){}
[Key]
[Required]
public virtual int CardId { get; set; }
[ForeignKey("StageId")]
public virtual Stage Stage { get; set; }
public int StageId { get; set; }
}
}
And a Stage class:
public class Stage
{
[Key]
public virtual int StageId { get; set; }
[DataMember(EmitDefaultValue = true)]
public string Name { get; set; }
public long Ticks { get; set; }
[NotMapped]
public TimeSpan Span
{
get { return TimeSpan.FromTicks(Ticks); }
}
// Make sure that these stages are generated accordingly
public static class Ids
{
// Zero
public const int One = 1;
// Ten Seconds
public const int Two = 2;
// One Minute
}
}
In my repository service I have an AddCard method:
public Card AddCard(Card card)
{
int parentId = 0;
Set parentSet = null;
if (card.ParentSetId.HasValue)
{
parentId = card.ParentSetId.Value;
parentSet = GetSet(parentId);
}
card.ParentSet = parentSet;
card.ParentSetId = parentSet.SetId;
card.StageId = Stage.Ids.One; // Set Id here with hopes of getting card.Stage to resolve as a nav property
_db.Cards.Add(card);
SaveChanges();
return card;
}
But for some reason, all of my Cards have a null value for Card.Stage - where Card.StageId is always some integer. I'm trying to get the navigation property working so I can access properties of the Stage through a Card.
What have I done wrong here?
Update:
The property is null when I try to access them via my test. First I create the card (in my test code):
var cardDto = new CardDto // Works!
{
Details = "Test Card",
};
Then I send it to my Dto Service (also in test code):
var fullCardDto = _service.AddCard(cardDto); // breaks because Stage is null when stageId is not
CardDto Class:
public class CardDto
{
public CardDto(){}
public CardDto(Card card)
{
CardId = card.CardId;
Stage = card.Stage.Name; // Fails here on its way back - creating the initial DTO works
Details = card.Details;
}
[Key]
[DataMember(EmitDefaultValue = true)]
public int CardId { get; set; }
[DataMember(EmitDefaultValue = true)]
public string Stage { get; set; }
[DataMember(IsRequired = false)]
public string Details { get; set; }
public Card ToEntity()
{
var newCard = new Card
{
CardId = CardId,
Details = Details,
};
return newCard;
}
_service is DTO service:
public CardDto AddCard(CardDto card)
{
return new CardDto(_repository.AddCard(card.ToEntity()));
}
_repository
code is above.
This works all the way through the _repository call, but if I debug the _repository.AddCard method, StageId has a value after I call SaveChanges(), but Stage does not.
The Card is passed back up the chain until it's supposed to be converted to a Dto again, where it fails due to the null Stage.
What's odd is that this code works outside of the test - if I use a client to hit AddCard, I get a card back without any errors.
Upvotes: 0
Views: 698
Reputation: 21366
To make Lazy loading to work you need to have a proxy created. If you are loading Card though
the EF you will automatically received a object wrapped in a proxy object. You can do two things here
1. To you use lazy loading you can create a proxy like this,
public Card AddCard(Card card)
{
var cardProxy= _db.Cards.Create();
//and copy all values from card to cardProxy here..
int parentId = 0;
Set parentSet = null;
if (cardProxy.ParentSetId.HasValue)
{
parentId = cardProxy.ParentSetId.Value;
parentSet = GetSet(parentId);
}
cardProxy.ParentSet = parentSet;
cardProxy.ParentSetId = parentSet.SetId;
cardProxy.StageId = Stage.Ids.One; // Set Id here with hopes of getting card.Stage to resolve as a nav property
SaveChanges();
return cardProxy;
}
Or you can use explicit loading,
public Card AddCard(Card card) { int parentId = 0; Set parentSet = null; if (card.ParentSetId.HasValue) { parentId = card.ParentSetId.Value; parentSet = GetSet(parentId); }
card.ParentSet = parentSet;
card.ParentSetId = parentSet.SetId;
card.StageId = Stage.Ids.One; // Set Id here with hopes of getting card.Stage to resolve as a nav property
_db.Cards.Add(card);
SaveChanges();
context.Entry(card).Reference(p => p.Stage).Load();//load stage here
return card;
}
Upvotes: 1