View models to Entity Framework v4 entities

Jan 20, 2011 at 12:01 AM

First of all, let me say I am very happy with the ValueInjecter as it is. Besides the core project I also like that you took some time and compiled together some great samples for it. The View model to Entity and versa samples are great, pretty self explanatory and easy to understand.

Unfortunately, there are no samples using EFv4 entities. Those entities are a little bit special because they (by default) include a foreign key column in the entity that references another entity (like your Person - Country example). In EFv4 you would probably have the country_id property on the Person entity and also the Country navigation property (reference to the Country object). When doing injection from View model to an existing entity (Update scenario) this Country reference should be left untouched because if we change anything we will for sure run into the "cannot insert duplicate primary key" or "cannot change the primary key of an entity". Only the foreign key property should be changed. Then the EF does its thing when calling SaveChanges() and autoloads the required entity based on the changed foreign key property value.

What I've came up with is this:

	public class LookupToPostCode : LoopValueInjection<PostCodeViewModelPostCode>
{
protected override PostCode SetValue(object sourcePropertyValue)
{
var selectedValue = ((string[])sourcePropertyValue)[0];
return new EntityFrameworkPostCodeProvider().Load(selectedValue);
}
}

But:

1. This pulls out the existing PostCode row and changes the entire reference. PostCode EF entity has postalcode and postname properties. Postalcode property is the primary key and is included in the referencing entity as postalcode foreign key. I would like to change only this foreign key if possible.

2. If the 1.) is not possible then I would like to remove the dependency on my typed provider in the value injection class and inject it via Ninject. How can I do that?

Jan 20, 2011 at 7:30 AM

It would be easier for me to understand if you would show something like:

public class Foo{

public string Name {get;set;}
public int CountryId {get;set;}

public Country Country {get;set;}

}

public class Bar {

public string Name {get;set;}

public CountryViewModel Country {get;set;}

}

 

and now to tell me which properties from Foo you would like to be injected in Bar and any other conditions

 

Jan 20, 2011 at 7:43 PM
Edited Jan 20, 2011 at 7:46 PM

This is a sample how my classes look like. They were shorten for the sake of brevity. What the injection should do is not touch the PostCode and PostCodeReference properties in the Client entity and just change the postalcode property (inject it from the ClientViewModel object's PostCode).


public class ClientViewModel
{
public PostCodeViewModel PostCode
{
get;
set;
}
}

public class PostCodeViewModel
{
public string postalcode
{
get;
set;
}

public string postname
{
get;
set;
}
}


//  this is extracted from EFv4 designer generated code
public partial class Client : EntityObject
{
#region Factory Method

/// <summary>
/// Create a new Client object.
/// </summary>
/// <param name="postalcode">Initial value of the postalcode property.</param>
public static Client CreateClient(global::System.String postalcode)
{
Client client = new Client();
client.postalcode = postalcode;
return client;
}

/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty = false, IsNullable = false)]
[DataMemberAttribute()]
public global::System.String postalcode
{
get
{
return _postalcode;
}
set
{
OnpostalcodeChanging(value);
ReportPropertyChanging("postalcode");
_postalcode = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("postalcode");
OnpostalcodeChanged();
}
}
private global::System.String _postalcode;
partial void OnpostalcodeChanging(global::System.String value);
partial void OnpostalcodeChanged();

#region Navigation Properties

/// <summary>
/// No Metadata Documentation available.
/// </summary>
[XmlIgnoreAttribute()]
[SoapIgnoreAttribute()]
[DataMemberAttribute()]
[EdmRelationshipNavigationPropertyAttribute("BusinessNext.Model.Ef", "FK_Clients_PostCodes", "PostCode")]
public PostCode PostCode
{
get
{
return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<PostCode>("BusinessNext.Model.Ef.FK_Clients_PostCodes", "PostCode").Value;
}
set
{
((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<PostCode>("BusinessNext.Model.Ef.FK_Clients_PostCodes", "PostCode").Value = value;
}
}
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[BrowsableAttribute(false)]
[DataMemberAttribute()]
public EntityReference<PostCode> PostCodeReference
{
get
{
return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<PostCode>("BusinessNext.Model.Ef.FK_Clients_PostCodes", "PostCode");
}
set
{
if ((value != null)) {
((IEntityWithRelationships)this).RelationshipManager.InitializeRelatedReference<PostCode>("BusinessNext.Model.Ef.FK_Clients_PostCodes", "PostCode", value);
}
}
}

#endregion
}
Jan 21, 2011 at 10:08 AM

I've created another page where I explain step by step how the valueinjecter works

http://valueinjecter.codeplex.com/wikipage?title=step%20by%20step%20explanation&referringTitle=Home

please let me know if it helped,

if not or not enough, tell me and I'll add some more cases

 

 

Jan 22, 2011 at 11:52 AM

I think I know how the custom value injections work. Thanks for this additional content but those are quite simplistic. I have everything working for simple entities. My example is geared toward EFv4 entities. Those entities have constraints on them that makes injecting a bit harder. Until you try it out for yourself you will have trouble understanding what I mean. Hopefully you will find some time to check it out and maybe expand the samples with some on EFv4.

Jan 22, 2011 at 2:47 PM

from the code I saw, you want to inject from an instance of ClientViewModel to Client

in the ClientViewModel I see only 1 property PostCode of type PostCodeViewModel, and there so no such property in Client

so using the default InjectFrom nothing is going to happen at all

I need to know exactly from which class to which one you want to inject and how the values of the properties should

e.g. (you could show manual mapping as an example)

client.Code = clientVM.PostCode

client.Man = clientVm.Woman

stuff like that

Jan 22, 2011 at 3:01 PM
Edited Jan 22, 2011 at 3:01 PM

Hava you actually looked closely at the code posted above? PostCode is there in Client and it is a navigation property. There is also postalcode property in Client. postalcode property should be updated from PostCodeViewModel.postalcode.

Jan 22, 2011 at 5:08 PM

yes, I did looked, tried to compile it, it's a lot of unnecessary code in there for me to know for the purpose of mapping

anyway

the best thing would be if you would show how you would do it manually so that I could show this via valueinjecter

Jan 22, 2011 at 5:56 PM
Edited Jan 22, 2011 at 5:57 PM

Yes, the code doesn't compile.

What I want to do is this:

client.postalcode = clientvm.PostCode.postalcode;

I could do this manually but I will have many more similar mapping like this in the future so I would like to have it implemented via InjectFrom<>..

Jan 22, 2011 at 6:18 PM

you could do this via an injection but you would not get anything from removing 1 line of code with another one

c.postCode = clientvm.PostCode.postalcode

or

c.InjectFrom<PostCode_postalcodeTopostCode>(clientvm)

it's still 1 line

usually injections are done to cover more properties at the same time, sometimes 1-to-1 but if you have the same combination of setting the value

in many different pairs of classes, e.g.

foo.Country = bar.CountryId

foo.Country = jar.CountryId

boo.Country = bar.CountryId etc.

if you have something like this, please show me something like the bigger picture, but if it's just this 1-to-1 property in this single pair of classes, no conventions can be found than it doesn't really makes sense to do an injection for it