I'm having huge difficulties getting my navigation properties to work in EF Code First. As an abstracted example, I have:
public class Parent{
public int ParentID {get; set;}
public virtual List<NamedChild> Children {get; set;}
public Parent(){}
public void Init(int ParentID, List<UnnamedChild> Children){
this.ParentID = ParentID;
this.Children = Children.ConvertAll(x => new NamedChild(x, ""));
}
}
public class NamedChild{
public int ChildID {get; set;}
public string Name {get; set;}
public NamedChild(UnnamedChild c, string Name){
this.ChildID = c.ChildID;
this.Name = Name;
}
}
public class UnnamedChild{
public int ChildID {get; set;}
public UnnamedChild(int ChildID){
this.ChildID = ChildID;
}
}
and then later...
List<UnnamedChild> children = GetChildrenFromSomewhere();
Parent p = db.Parents.Create();
p.Init(1, children);
db.Parents.Add(p);
db.SaveChanges();
Now if I'm debugging I can look into the current DbSet and it shows that there is 1 Parent, and its "Children" property is set to a List of 2 NamedChild. This is good, this is what it should be. However, if I stop the program and re-run it, when I look in the DbSet there is still 1 Parent, but its "Children" property has been set to null.
In summary, immediately after saving it the values are right, but as soon as I re-load the DB Context those values are missing (nulls). I am running the most recent EF with LazyLoading enabled.
It should be noted that if I use .Include(), it will populate those null values with the proper NamedChild list, but I need this to work with LazyLoading.
I think EF is probably unable to create a proxy for NamedChild objects, and can't perform any lazy loading as a result.
One of the requirements for creating a proxy class is that your POCO must have a public/protected constructor without parameters.
This may solve your problem:
public class NamedChild
{
public int ChildID {get; set;}
public string Name {get; set;}
protected NamedChild() {}
public NamedChild(UnnamedChild c, string Name)
{
this.ChildID = c.ChildID;
this.Name = Name;
}
}
I believe you already meet all the other requirements for lazy loading proxies.
Full Requirements here:
http://msdn.microsoft.com/en-us/library/vstudio/dd468057%28v=vs.100%29.aspx
Although I don't think it should technically matter, I've noticed that EF seems to prefer ICollections to other list/array types. Try:
public virtual ICollection<NamedChild> Children {get; set;}
Also, I'm a little confused about what you're trying to achieve with your custom constructors. It seems that all you're doing is initializing the properties on the instance. If that's the case, a custom constructor is not needed. Just use the class initialization syntax:
x => new NamedChild { ChildId = x.ChildId, Name = "" }
Related
Using Entity Framework and having the following class:
public class TestClass{
[Key]
public int id {get; set;}
public int foreignId {get; set;}
[ForeignKey("foreignId")
public MyObject myObject {get; set;}
}
With this class I want to save the "TestClass" but the entity framework first tries to save/create the "myObject" that doesn't need to get saved because it's only a reference.
In some forums (enter link description here) I read that I has to set the myObject explicitely to "null" before saving, but in my opinition this is quite annoying.
So I want to ask if there is any annotation or something like "IgnoreOnSave" that I can add to the myObject?
[ForeignKey("foreignId", "ignoreOnSave")]
public MyObject myObject {get; set;}
Update
[NotMapped] did it for me:
[NotMapped]
[ForeignKey("foreignId")]
public MyObject myObject {get; set;}
With this attribute I can load the object with the foreign sub object, but on saving the subObject "myObject" is ignored. I only need to assure in code, that the ID of "myObject" is copied to the foreign-key-property of the main object.
Additionally (I'm creating a Web-Api-Solution) I added a [JsonIgnore] to the foreign-key-property so that I have clean interfaces.
Update
Using [NotMapped]leads to that the linq expression ".include" can't be used for the respective properties anymore.
I have three database tables which represent comparison scores for common name strings. They're separated into individual tables to speed scanning time. All of them share the same basic structure of four columns: an ID, two strings and score represtning how different the strings are.
The DB is accessed via Entity Framework. In the implementation code, this leads me to having three near-identitical functions, one for each object type:
private bool CheckSurnameJw(string string1, string string2, double threshold)
{
JwDistanceSurname jw = _rep.GetJwDistanceSurname(string1, string2);
if (jw == null)
{
double dist = JaroWinklerProximity(string1, string2);
JwDistanceSurname newJw = new JwDistanceSurname { Surname1 = string1, Surname2 = string2, JwScore = dist };
_rep.Update(newJw);
_rep.SaveChanges();
return dist >= surnameProximityThreshold;
}
else
{
return jw.JwScore >= threshold;
}
}
Looking at this, while I could nip and tuck slightly, I can't see any clear areas where the function could be sensibly improved by farming code out to another function. But it annoys the hell out of me to have to re-implement the same logic block three times, to deal with three different identity types.
I wrapped all three classes in an interface specifiying the four columns to see if that would help me tidy things up. But it doesn't: I can't use a generic "get" function because each is querying a different table and, likewise, when I create a new instance of the class I need to give it the appropriate type.
Is there a way I can improve this using reflection/generics?
If your four columns all have the same columnNames, I'd definitely go for inheritance using Table Per Type or some kind of Composition
However, if the four columns do not have a common meaning, I'd use an interface.
Table per Type approach
Use this if the four columns represent typically the same thing and you would think that your tables are special kinds of this common thing:
abstract class Common
{
public string String1 {get; set;}
public string string2 {get; set;}
public double Threshold {get; set;}
}
class Table1 : Common
{
public int Id {get; set;}
...
}
class Table2 : Common
{
public int Id {get; set;}
...
}
Your DbContext will be like:
class MyDbContext : DbContext
{
public DbSet<Table1> Table1s {get; set;}
public DbSet<Table2> Table2s {get; set;}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Table1>().ToTable("Table1s");
modelBuilder.Entity<Table2>().ToTable("Table2s");
}
}
This is enough for entity framework to design two tables, where each table has the four common columns.
A DbSet represents the table in the database. The database doesn't know how CheckSurName. Hence I choose not to let class Common know how to CheckSurName. I create an extension function of Common instead.
See Extension Methods Demystified
static class CommonExtensions
{
public static bool CheckSurName(this Common common)
{
JwDistanceSurname jw = _rep.GetJwDistanceSurname(common.String1, common.String2);
...
}
}
Usage:
IEnumerable<Table1> myTableCollection = myDbContext.Table1s
.Where(table => table...)
foreach (Table1 table1 in myTableCollection)
{
bool surNameOk = table1.CheckSurName();
Process(surNameOk);
}
Composition Approach
As most developers, I favour composition over inheritance. The approach will be similar, but instead of Inheritance composition is used
class Common ...
class Table1
{
public int Id {get; set;}
public Common Common {get; set;}
}
etc. This will also lead to one Table per type, every table containing all Common properties. The extension function will be similar. The only difference is that you don't perform the check on surnames on your retrieve tables, but on the Common of your retrieved tables:
IEnumerable<Table1> retrievedTables = ...
foreach (Table1 table in retrievedTables)
{
bool SurnameOk = table1.Common.CheckSurName();
...
}
If Common represents something like a person, and your tables represents Items that have a Person, like a SchoolClass with a Teacher, and a School with a HeadMaster, I'd definitely go for this approach. After all a School is not a Person.
Interface approach
You described your columns as if only their types where common, not the names, nor their meaning. You just have two strings and one double, (and an Id, which is lost in your CheckSurName), and the only common thing is that they are two strings and a double. In that case I'd go for an Interface.
Objects that have properties that are needed to CheckSurName will implement ISurNameCheckable:
interface ISurnameCheckable
{
public string String1 {get;}
public string String2 {get;}
public double Threshold {get;}
}
class Table1 : ISurnameCheckable
{
public int Id {get; set;}
public string Street {get; set;}
public string City {get; set}
// implementation of ISurnameCheckable
public string String1 {get{return this.Street;}}
public string String2 {get{return this.City;}}
...
}
The extension function is almost the same:
public static bool CheckSurName(this ISurnameCheckable surnameCheckable)
{
JwDistanceSurname jw = _rep.GetJwDistanceSurname(
surnameCheckable.String1, surnameCheckable.String2);
...
}
I have a class
public class Level1
{
public int Id {get; set;}
public virtual List<Level2> Level2List {get; set;}
}
public class Level2
{
public int Id {get; set;}
public int Level3Id {get; set;}
public virtual Level3 Level3 {get; set;}
}
public class Level3
{
public int Id {get; set;}
public string Name {get; set;}
}
Using navigation properties i could load List<Level2> like this
var myList = _myLevel1Repository.GetSingle(x=>x.Id == Level1Id, x=>x.Level2List);
but how do I load Level3 and its properties that is linked with Level2?
PS: Lazy loading is not possible.
This is the Getsingle function
public T GetSingle(Func<T, bool> where, params Expression<Func<T, object>>[] navProps)
{
T item = null;
using (var context = new MyDbContext())
item = GetFilteredSet(context, navProps).AsNoTracking().FirstOrDefault(where);
return item;
}
Your GetSingle method should be this way:
public T GetSingle(Func<T, bool> where, params Expression<Func<T, object>>[] navProps)
{
T item = null;
using (var context = new MyDbContext())
{
IQueryable<T> query = context.Set<T>();
//Include the navigations properties as part of the query
if (navProps!= null)
{
query = navProps.Aggregate(query, (current, include) => current.Include(include));
}
item = query.Where(where).FirstOrDefault();
}
return item;
}
I don't know what are you doing in the GetFilteredSet method, but I guess you can reorganize the code I show above at your convenience. The key to include more than one level of nav. properties in EF is use the Include method. When you use this method you are going to load the nav. properties as part of your query (check eager loading section in this link). Now, there are two Include methods :
DbQuery.Include Method
Whit this method you need to pass the path of the nav. properties you want to load as an string, for example, in your case, it would be:
context.Set<Level1>.Include("Level2List.Level3");
DbExtensions.Include extension method
This is the method that I use in my above code where you can specify the related objects to include using a lambda expression. IMHO this is the best variant because is strongly typed, and if you change some of the nav. properties name in your entities, you are also going to receive a compilation error(s). In the link I share above, you can see all the patterns you can use to include different levels of nav. properties.
context.Set<Level1>.Include(l1=>l1.Level2List.Select(l2=>l2.Level3));
Returning to the initial problem, now you can use your GetSingle method to include more than one level this way:
var entity= _myLevel1Repository.GetSingle(x=>x.Id == Level1Id, x=>x.Level2List.Select(l2=>l2.Level3));
How about using include?
var mylevel1s = _db.Level1(x=>x.Id == Level1Id).Include(x=> x.Level2List.Select(a=>a.Level3));
Ive searched for this for few days now and cant seem to get anything to work, I am using c# MVC Entity Framework with Automapper and im trying to achieve the below ViewModels (mainly LostDocumentVM) to be mapped from my database, all other properties will be set in controllers.
Here is my ViewModels...
DocumentVM
{
Public Enum.HistoricType HistoricType {get;set;}
Public DocumentChildVM Document { get; set;}
}
DocumentChildVM
{
Public bool ShowHistoricLink {get;set;}
Public IEnumerable<ListDocumentVM> DocumentsToReview {get;set;}
}
ListDocumentVM
{
Public int Id {get;set;}
Public string Name {get; set;}
Public DateTime? ReviewDate {get;set;}
}
I initialise the DocumentVM like this...
DocumentVM documentVM = DataContext.SystemUser.Where(x=>x.SustemUserID==LoggedOnUserID).Project().To<DocumentVM>().SingleOrDefault();
And my mapping is like this...
Mapper.CreateMap<SystemUser,DocumentVM>()
.ForMember(dest=>dest.Document.DocumentsToReview, opt=>opt.MapFrom(src=>src.Documents.Where(x=>x.DocumentType == Enum.DocumentType.Assessment));
Im new to AutoMapper and struggling to get more advanced mappings to work.
Yes, your ForMember member must refer to a member on the destination type, and yours is referring to a member on the child type. Instead, you'll need to create an AfterMap function that fills in this information on that child entity.
It's not difficult, but you have a bit of a strange set up where a child object Document has a property DocumentsToReview from another property on the parent DocumentVM:
documentVM.Document.DocumentsToReview =
src.Documents.Where(doc => doc.DocumentType == Enum.DocumentType.Assessment);
When you have to shuffle data between sibling/nephew members, it gets a little more challenging.
To do this with AfterMap:
Mapper.CreateMap<SystemUser, DocumentVM>()
.AfterMap((src, dest) => dest.Document.DocumentsToReview =
src.Documents.Where(doc => doc.DocumentType == Enum.DocumentType.Assessment));
In a situation where an EntitySet is being queried (in, say, a many-to-many relationship), is it possible to access the parent object?
e.g
Thing thing = db.Things.First();
Widget widget = thing.Widgets.First();
// Let's assume that Widgets can have many things as well
// (i.e. widget.Things is possible)
widget.ParentThing // would return the same instance of thing used above
Is that possible?
is it possible to access the parent object
With a many-to-many there really isn't a "parent" - there are multiple related objects. A many-to-many is usually modeled with navigation properties:
public class Thing
{
public int ID {get; set;}
public virtual IEnumerable<Widget> Widgets {get; set;}
}
public class Widget
{
public int ID {get; set;}
public virtual IEnumerable<Thing> Things {get; set;}
}
If your model doesn't have such properties then an alternative is to go back to the context (or back to the db if you don't have the context anymore):
var relatedThings = db.Things
.Where(t => t.Widgets.Any(w => ID == widget.ID));